Snapshot of commit d5ec1d5018ed24f1b4f32b1d09df6dbd7e2fc425

from branch master of git://git.jetbrains.org/idea/community.git
diff --git a/java/debugger/impl/debugger-impl.iml b/java/debugger/impl/debugger-impl.iml
new file mode 100644
index 0000000..8b9d265
--- /dev/null
+++ b/java/debugger/impl/debugger-impl.iml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module relativePaths="true" type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="module" module-name="debugger-openapi" exported="" />
+    <orderEntry type="module" module-name="openapi" />
+    <orderEntry type="module" module-name="execution-openapi" />
+    <orderEntry type="module" module-name="resources" />
+    <orderEntry type="module" module-name="xdebugger-api" />
+    <orderEntry type="module" module-name="xdebugger-impl" />
+    <orderEntry type="module" module-name="lang-api" />
+    <orderEntry type="module" module-name="compiler-openapi" />
+    <orderEntry type="module" module-name="java-runtime" />
+    <orderEntry type="module" module-name="jsp-openapi" />
+    <orderEntry type="module" module-name="java-impl" />
+  </component>
+  <component name="copyright">
+    <Base>
+      <setting name="state" value="1" />
+    </Base>
+  </component>
+</module>
+
diff --git a/java/debugger/impl/src/com/intellij/debugger/DebugEnvironment.java b/java/debugger/impl/src/com/intellij/debugger/DebugEnvironment.java
new file mode 100644
index 0000000..af8662b
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/DebugEnvironment.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2000-2012 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.debugger;
+
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.ExecutionResult;
+import com.intellij.execution.configurations.RemoteConnection;
+import com.intellij.psi.search.GlobalSearchScope;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: michael.golubev
+ */
+public interface DebugEnvironment {
+
+  @Nullable
+  ExecutionResult createExecutionResult() throws ExecutionException;
+
+  GlobalSearchScope getSearchScope();
+
+  boolean isRemote();
+
+  RemoteConnection getRemoteConnection();
+
+  boolean isPollConnection();
+
+  String getSessionName();
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/DebugException.java b/java/debugger/impl/src/com/intellij/debugger/DebugException.java
new file mode 100644
index 0000000..c92b9b5
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/DebugException.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * @author Eugene Zhuravlev
+ */
+package com.intellij.debugger;
+
+public class DebugException extends RuntimeException {
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  public DebugException() {
+    super("DebugException");
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/DebugUIEnvironment.java b/java/debugger/impl/src/com/intellij/debugger/DebugUIEnvironment.java
new file mode 100644
index 0000000..8c89bad
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/DebugUIEnvironment.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2000-2012 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.debugger;
+
+import com.intellij.diagnostic.logging.LogFilesManager;
+import com.intellij.execution.configurations.RunProfile;
+import com.intellij.execution.ui.RunContentDescriptor;
+import com.intellij.openapi.actionSystem.DefaultActionGroup;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: michael.golubev
+ */
+public interface DebugUIEnvironment {
+
+  DebugEnvironment getEnvironment();
+
+  @Nullable
+  RunContentDescriptor getReuseContent();
+
+  @Nullable
+  Icon getIcon();
+
+  void initLogs(RunContentDescriptor content, LogFilesManager logFilesManager);
+
+  void initActions(RunContentDescriptor content, DefaultActionGroup actionGroup);
+
+  @Nullable
+  RunProfile getRunProfile();
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/DebuggerInvocationUtil.java b/java/debugger/impl/src/com/intellij/debugger/DebuggerInvocationUtil.java
new file mode 100644
index 0000000..c0dfbb9
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/DebuggerInvocationUtil.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2000-2009 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.debugger;
+
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.ModalityState;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Computable;
+import com.intellij.psi.PsiDocumentManager;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+
+public class DebuggerInvocationUtil {
+  public static void swingInvokeLater(final Project project, @NotNull final Runnable runnable) {
+    SwingUtilities.invokeLater(new Runnable() {
+      public void run() {
+        if (project != null && !project.isDisposed()) {
+          runnable.run();
+        }
+      }
+    });
+  }
+  public static void invokeLater(final Project project, @NotNull final Runnable runnable) {
+    ApplicationManager.getApplication().invokeLater(new Runnable() {
+      public void run() {
+        if (project != null && !project.isDisposed()) {
+          runnable.run();
+        }
+      }
+    });
+  }
+
+  public static void invokeLater(final Project project, @NotNull final Runnable runnable, ModalityState state) {
+    ApplicationManager.getApplication().invokeLater(new Runnable() {
+      public void run() {
+        if(project == null || project.isDisposed()) return;
+
+        runnable.run();
+      }
+    }, state);
+  }
+
+  public static void invokeAndWait(final Project project, @NotNull final Runnable runnable, ModalityState state) {
+    ApplicationManager.getApplication().invokeAndWait(new Runnable() {
+      public void run() {
+        if(project == null || project.isDisposed()) return;
+
+        runnable.run();
+      }
+    }, state);
+  }
+
+  public static  <T> T commitAndRunReadAction(Project project, final EvaluatingComputable<T> computable) throws EvaluateException {
+    final Throwable[] ex = new Throwable[] { null };
+    T result = PsiDocumentManager.getInstance(project).commitAndRunReadAction(new Computable<T>() {
+          public T compute() {
+            try {
+              return computable.compute();
+            }
+            catch (RuntimeException e) {
+              ex[0] = e;
+            }
+            catch (Exception th) {
+              ex[0] = th;
+            }
+
+            return null;
+          }
+        });
+
+    if(ex[0] != null) {
+      if(ex[0] instanceof RuntimeException) {
+        throw (RuntimeException)ex[0];
+      }
+      else {
+        throw (EvaluateException) ex[0];
+      }
+    }
+
+    return result;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/DebuggerManagerEx.java b/java/debugger/impl/src/com/intellij/debugger/DebuggerManagerEx.java
new file mode 100644
index 0000000..0384e6e
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/DebuggerManagerEx.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2000-2009 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.debugger;
+
+import com.intellij.debugger.engine.DebugProcess;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerManagerListener;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.debugger.impl.DebuggerStateManager;
+import com.intellij.debugger.ui.breakpoints.BreakpointManager;
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.Executor;
+import com.intellij.execution.configurations.ModuleRunProfile;
+import com.intellij.execution.configurations.RemoteConnection;
+import com.intellij.execution.configurations.RunProfileState;
+import com.intellij.execution.runners.ProgramRunner;
+import com.intellij.openapi.project.Project;
+
+import java.util.Collection;
+
+public abstract class DebuggerManagerEx extends DebuggerManager {
+  public static DebuggerManagerEx getInstanceEx(Project project) {
+    return (DebuggerManagerEx)DebuggerManager.getInstance(project);
+  }
+  public abstract BreakpointManager  getBreakpointManager();
+
+  public abstract Collection<DebuggerSession> getSessions();
+  public abstract DebuggerSession getSession(DebugProcess debugProcess);
+
+  public abstract DebuggerContextImpl getContext();
+  public abstract DebuggerStateManager getContextManager();
+
+  public abstract void addDebuggerManagerListener(DebuggerManagerListener debuggerManagerListener);
+  public abstract void removeDebuggerManagerListener(DebuggerManagerListener debuggerManagerListener);
+
+  public abstract DebuggerSession attachVirtualMachine(Executor executor, 
+                                                       ProgramRunner runner,
+                                                       ModuleRunProfile profile,
+                                                       RunProfileState state,
+                                                       RemoteConnection connection,
+                                                       boolean pollConnection
+  ) throws ExecutionException;
+
+  public abstract DebuggerSession attachVirtualMachine(DebugEnvironment environment) throws ExecutionException;
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/DefaultDebugEnvironment.java b/java/debugger/impl/src/com/intellij/debugger/DefaultDebugEnvironment.java
new file mode 100644
index 0000000..dc2e1af
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/DefaultDebugEnvironment.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2000-2012 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.debugger;
+
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.ExecutionResult;
+import com.intellij.execution.Executor;
+import com.intellij.execution.configurations.*;
+import com.intellij.execution.filters.ExceptionFilters;
+import com.intellij.execution.filters.Filter;
+import com.intellij.execution.filters.TextConsoleBuilder;
+import com.intellij.execution.runners.ProgramRunner;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.search.GlobalSearchScope;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: michael.golubev
+ */
+public class DefaultDebugEnvironment implements DebugEnvironment {
+
+  private final GlobalSearchScope mySearchScope;
+  private final Executor myExecutor;
+  private final ProgramRunner myRunner;
+  private RunProfileState myState;
+  private final RemoteConnection myRemoteConnection;
+  private final boolean myPollConnection;
+  private final RunProfile myRunProfile;
+
+  public DefaultDebugEnvironment(Project project,
+                                 Executor executor,
+                                 ProgramRunner runner,
+                                 RunProfile runProfile,
+                                 RunProfileState state,
+                                 RemoteConnection remoteConnection,
+                                 boolean pollConnection) {
+    myExecutor = executor;
+    myRunner = runner;
+    myRunProfile = runProfile;
+    myState = state;
+    myRemoteConnection = remoteConnection;
+    myPollConnection = pollConnection;
+
+    mySearchScope = createSearchScope(project, runProfile);
+  }
+
+  @NotNull
+  public static GlobalSearchScope createSearchScope(Project project, RunProfile runProfile) {
+    Module[] modules = null;
+    if (runProfile instanceof ModuleRunProfile) {
+      modules = ((ModuleRunProfile)runProfile).getModules();
+    }
+    if (modules == null || modules.length == 0) {
+      return GlobalSearchScope.allScope(project);
+    }
+    else {
+      GlobalSearchScope scope = GlobalSearchScope.moduleRuntimeScope(modules[0], true);
+      for (int idx = 1; idx < modules.length; idx++) {
+        Module module = modules[idx];
+        scope = scope.uniteWith(GlobalSearchScope.moduleRuntimeScope(module, true));
+      }
+      return scope;
+    }
+  }
+
+  @Override
+  public ExecutionResult createExecutionResult() throws ExecutionException {
+    if (myState instanceof CommandLineState) {
+      final TextConsoleBuilder consoleBuilder = ((CommandLineState)myState).getConsoleBuilder();
+      if (consoleBuilder != null) {
+        List<Filter> filters = ExceptionFilters.getFilters(mySearchScope);
+        for (Filter filter : filters) {
+          consoleBuilder.addFilter(filter);
+        }
+      }
+    }
+    return myState.execute(myExecutor, myRunner);
+  }
+
+  @Override
+  public GlobalSearchScope getSearchScope() {
+    return mySearchScope;
+  }
+
+  @Override
+  public boolean isRemote() {
+    return myState instanceof RemoteState;
+  }
+
+  @Override
+  public RemoteConnection getRemoteConnection() {
+    return myRemoteConnection;
+  }
+
+  @Override
+  public boolean isPollConnection() {
+    return myPollConnection;
+  }
+
+  @Override
+  public String getSessionName() {
+    return myRunProfile.getName();
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/DefaultDebugUIEnvironment.java b/java/debugger/impl/src/com/intellij/debugger/DefaultDebugUIEnvironment.java
new file mode 100644
index 0000000..cacbf8e
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/DefaultDebugUIEnvironment.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2000-2012 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.debugger;
+
+import com.intellij.diagnostic.logging.LogFilesManager;
+import com.intellij.diagnostic.logging.OutputFileUtil;
+import com.intellij.execution.Executor;
+import com.intellij.execution.configurations.RemoteConnection;
+import com.intellij.execution.configurations.RunConfigurationBase;
+import com.intellij.execution.configurations.RunProfile;
+import com.intellij.execution.configurations.RunProfileState;
+import com.intellij.execution.process.ProcessHandler;
+import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.execution.runners.ProgramRunner;
+import com.intellij.execution.runners.RestartAction;
+import com.intellij.execution.ui.RunContentDescriptor;
+import com.intellij.execution.ui.actions.CloseAction;
+import com.intellij.ide.actions.ContextHelpAction;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.actionSystem.Constraints;
+import com.intellij.openapi.actionSystem.DefaultActionGroup;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Disposer;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: michael.golubev
+ */
+public class DefaultDebugUIEnvironment implements DebugUIEnvironment {
+
+  private final Project myProject;
+  private final Executor myExecutor;
+  private final ProgramRunner myRunner;
+  private final ExecutionEnvironment myExecutionEnvironment;
+  @Nullable private RunContentDescriptor myReuseContent;
+  private final RunProfile myRunProfile;
+  private final DebugEnvironment myModelEnvironment;
+
+  public DefaultDebugUIEnvironment(Project project,
+                                   Executor executor,
+                                   ProgramRunner runner,
+                                   ExecutionEnvironment environment,
+                                   RunProfileState state,
+                                   @Nullable RunContentDescriptor reuseContent,
+                                   RemoteConnection remoteConnection,
+                                   boolean pollConnection) {
+    myProject = project;
+    myExecutor = executor;
+    myRunner = runner;
+    myExecutionEnvironment = environment;
+    myRunProfile = environment.getRunProfile();
+    myModelEnvironment = new DefaultDebugEnvironment(project,
+                                                     executor,
+                                                     runner,
+                                                     myRunProfile,
+                                                     state,
+                                                     remoteConnection,
+                                                     pollConnection);
+    myReuseContent = reuseContent;
+    if (myReuseContent != null) {
+      Disposer.register(myReuseContent, new Disposable() {
+        @Override
+        public void dispose() {
+          myReuseContent = null;
+        }
+      });
+    }
+  }
+
+  @Override
+  public DebugEnvironment getEnvironment() {
+    return myModelEnvironment;
+  }
+
+  @Nullable
+  @Override
+  public RunContentDescriptor getReuseContent() {
+    return myReuseContent;
+  }
+
+  @Override
+  public Icon getIcon() {
+    return myRunProfile.getIcon();
+  }
+
+  @Override
+  public void initLogs(RunContentDescriptor content, LogFilesManager logFilesManager) {
+    ProcessHandler processHandler = content.getProcessHandler();
+    if (myRunProfile instanceof RunConfigurationBase) {
+      RunConfigurationBase runConfiguration = (RunConfigurationBase)myRunProfile;
+
+      logFilesManager.registerFileMatcher(runConfiguration);
+
+      logFilesManager.initLogConsoles(runConfiguration, processHandler);
+      OutputFileUtil.attachDumpListener(runConfiguration, processHandler, content.getExecutionConsole());
+    }
+  }
+
+  @Override
+  public void initActions(RunContentDescriptor content, DefaultActionGroup actionGroup) {
+    ProcessHandler processHandler = content.getProcessHandler();
+    RestartAction restartAction = new RestartAction(myExecutor,
+                                                    myRunner,
+                                                    processHandler,
+                                                    RestartAction.RERUN_DEBUGGER_ICON,
+                                                    content,
+                                                    myExecutionEnvironment);
+    actionGroup.add(restartAction, Constraints.FIRST);
+    restartAction.registerShortcut(content.getComponent());
+
+    actionGroup.add(new CloseAction(myExecutor, content, myProject));
+    actionGroup.add(new ContextHelpAction(myExecutor.getHelpId()));
+  }
+
+  @Override
+  public RunProfile getRunProfile() {
+    return myRunProfile;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/EvaluatingComputable.java b/java/debugger/impl/src/com/intellij/debugger/EvaluatingComputable.java
new file mode 100644
index 0000000..1abe53b
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/EvaluatingComputable.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2000-2009 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.debugger;
+
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+
+public interface EvaluatingComputable <T>{
+  T compute() throws EvaluateException;
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/HelpID.java b/java/debugger/impl/src/com/intellij/debugger/HelpID.java
new file mode 100644
index 0000000..0dd127d
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/HelpID.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * @author: Eugene Zhuravlev
+ * Date: Nov 12, 2002
+ * Time: 3:25:10 PM
+ */
+package com.intellij.debugger;
+
+import org.jetbrains.annotations.NonNls;
+
+public interface HelpID {
+  @NonNls String LINE_BREAKPOINTS = "debugging.lineBreakpoint";
+  @NonNls String METHOD_BREAKPOINTS = "debugging.methodBreakpoint";
+  @NonNls String EXCEPTION_BREAKPOINTS = "debugging.exceptionBreakpoint";
+  @NonNls String FIELD_WATCHPOINTS = "debugging.fieldWatchpoint";
+  @NonNls String EVALUATE = "debugging.debugMenu.evaluate";
+  @NonNls String EXPORT_THREADS = "reference.run.export.thread";
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/InstanceFilter.java b/java/debugger/impl/src/com/intellij/debugger/InstanceFilter.java
new file mode 100644
index 0000000..df0ff53d
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/InstanceFilter.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2000-2009 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.debugger;
+
+import com.intellij.openapi.util.DefaultJDOMExternalizer;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.JDOMExternalizable;
+import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.ui.classFilter.ClassFilter;
+import org.jdom.Element;
+
+/**
+ * User: lex
+ * Date: Aug 29, 2003
+ * Time: 2:49:27 PM
+ */
+public class InstanceFilter implements JDOMExternalizable{
+  public static final InstanceFilter[] EMPTY_ARRAY = new InstanceFilter[0];
+  
+  public long    ID      = 0;
+  public boolean ENABLED = true;
+
+  protected InstanceFilter(long ID, boolean ENABLED) {
+    this.ID = ID;
+    this.ENABLED = ENABLED;
+  }
+
+  public long getId() {
+    return ID;
+  }
+
+  public boolean isEnabled() {
+    return ENABLED;
+  }
+
+  public void setId(long id) {
+    ID = id;
+  }
+
+  public void setEnabled(boolean enabled) {
+    ENABLED = enabled;
+  }
+
+  public static InstanceFilter create(String pattern) {
+    return new InstanceFilter(Long.parseLong(pattern), true);
+  }
+
+  public static InstanceFilter create(final ClassFilter filter) {
+    return new InstanceFilter(Long.parseLong(filter.getPattern()), filter.isEnabled());
+  }
+
+  public void readExternal(Element element) throws InvalidDataException {
+    DefaultJDOMExternalizer.readExternal(this, element);
+  }
+
+  public void writeExternal(Element element) throws WriteExternalException {
+    DefaultJDOMExternalizer.writeExternal(this, element);
+  }
+
+  public static ClassFilter[] createClassFilters(InstanceFilter[] filters) {
+    ClassFilter [] cFilters = new ClassFilter[filters.length];
+    for (int i = 0; i < cFilters.length; i++) {
+      InstanceFilter instanceFilter = filters[i];
+
+      ClassFilter classFilter = new ClassFilter();
+      classFilter.setEnabled(instanceFilter.isEnabled());
+      classFilter.setPattern(Long.toString(instanceFilter.getId()));
+
+      cFilters[i] = classFilter;
+    }
+    return cFilters;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/AbstractSteppingActionHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/AbstractSteppingActionHandler.java
new file mode 100644
index 0000000..8fdcfb9
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/AbstractSteppingActionHandler.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.engine.SuspendContextImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.project.Project;
+import com.intellij.xdebugger.impl.actions.DebuggerActionHandler;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author nik
+ */
+public abstract class AbstractSteppingActionHandler extends DebuggerActionHandler {
+
+  @Nullable
+  protected static DebuggerSession getSession(@NotNull Project project) {
+    final DebuggerContextImpl context = getContext(project);
+    return context != null ? context.getDebuggerSession() : null;
+  }
+
+  @Nullable
+  private static DebuggerContextImpl getContext(@NotNull Project project) {
+    return (DebuggerManagerEx.getInstanceEx(project)).getContext();
+  }
+
+  public boolean isEnabled(@NotNull final Project project, final AnActionEvent event) {
+    final DebuggerContextImpl context = getContext(project);
+    if (context == null) {
+      return false;
+    }
+
+    DebuggerSession debuggerSession = context.getDebuggerSession();
+
+    final boolean isPaused = debuggerSession != null && debuggerSession.isPaused();
+    final SuspendContextImpl suspendContext = context.getSuspendContext();
+    final boolean hasCurrentThread = suspendContext != null && suspendContext.getThread() != null;
+    return isPaused && hasCurrentThread;
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/AddToWatchActionHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/AddToWatchActionHandler.java
new file mode 100644
index 0000000..8e95e99
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/AddToWatchActionHandler.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class AddToWatchActionHandler
+ * @author Jeka
+ */
+package com.intellij.debugger.actions;
+
+import com.intellij.debugger.DebuggerInvocationUtil;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.debugger.engine.events.DebuggerContextCommandImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.ui.DebuggerPanelsManager;
+import com.intellij.debugger.ui.impl.MainWatchPanel;
+import com.intellij.debugger.ui.impl.VariablesPanel;
+import com.intellij.debugger.ui.impl.WatchDebuggerTree;
+import com.intellij.debugger.ui.impl.watch.*;
+import com.intellij.idea.ActionsBundle;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.PlatformDataKeys;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.Messages;
+import com.intellij.xdebugger.impl.actions.DebuggerActionHandler;
+import com.intellij.xdebugger.impl.actions.XDebuggerActions;
+import org.jetbrains.annotations.NotNull;
+
+public class AddToWatchActionHandler extends DebuggerActionHandler {
+  @Override
+  public boolean isEnabled(@NotNull Project project, AnActionEvent event) {
+    DebuggerTreeNodeImpl[] selectedNodes = DebuggerAction.getSelectedNodes(event.getDataContext());
+    boolean enabled = false;
+    if (selectedNodes != null && selectedNodes.length > 0) {
+      if (DebuggerAction.getPanel(event.getDataContext()) instanceof VariablesPanel) {
+        enabled = true;
+        for (DebuggerTreeNodeImpl node : selectedNodes) {
+          NodeDescriptorImpl descriptor = node.getDescriptor();
+          if (!(descriptor instanceof ValueDescriptorImpl)) {
+            enabled = false;
+            break;
+          }
+        }
+      }
+    }
+    else {
+      final Editor editor = event.getData(PlatformDataKeys.EDITOR);
+      enabled = DebuggerUtilsEx.getEditorText(editor) != null;
+    }
+    return enabled;
+  }
+
+  @Override
+  public void perform(@NotNull Project project, AnActionEvent event) {
+    final DebuggerContextImpl debuggerContext = DebuggerAction.getDebuggerContext(event.getDataContext());
+
+    if(debuggerContext == null) return;
+
+    final DebuggerSession session = debuggerContext.getDebuggerSession();
+    if(session == null) {
+      return;
+    }
+    final MainWatchPanel watchPanel = DebuggerPanelsManager.getInstance(debuggerContext.getProject()).getWatchPanel();
+
+    if(watchPanel == null) {
+      return;
+    }
+
+    final DebuggerTreeNodeImpl[] selectedNodes = DebuggerAction.getSelectedNodes(event.getDataContext());
+
+    if(selectedNodes != null && selectedNodes.length > 0) {
+      addFromNodes(debuggerContext, watchPanel, selectedNodes);
+    }
+    else {
+      final Editor editor = event.getData(PlatformDataKeys.EDITOR);
+      if (editor != null) {
+        final TextWithImports editorText = DebuggerUtilsEx.getEditorText(editor);
+        if (editorText != null) {
+          doAddWatch(watchPanel, editorText, null);
+        }
+      }
+    }
+  }
+
+  public static void addFromNodes(final DebuggerContextImpl debuggerContext, final MainWatchPanel watchPanel, final DebuggerTreeNodeImpl[] selectedNodes) {
+    debuggerContext.getDebugProcess().getManagerThread().schedule(new AddToWatchesCommand(debuggerContext, selectedNodes, watchPanel));
+  }
+
+  public static void doAddWatch(final MainWatchPanel watchPanel, final TextWithImports expression, final NodeDescriptorImpl descriptor) {
+    final WatchDebuggerTree watchTree = watchPanel.getWatchTree();
+    final DebuggerTreeNodeImpl node = watchTree.addWatch(expression, null);
+    if (descriptor != null) {
+      node.getDescriptor().displayAs(descriptor);
+    }
+    node.calcValue();
+  }
+
+  private static class AddToWatchesCommand extends DebuggerContextCommandImpl {
+
+    private final DebuggerContextImpl myDebuggerContext;
+    private final DebuggerTreeNodeImpl[] mySelectedNodes;
+    private final MainWatchPanel myWatchPanel;
+
+    public AddToWatchesCommand(DebuggerContextImpl debuggerContext, DebuggerTreeNodeImpl[] selectedNodes, MainWatchPanel watchPanel) {
+      super(debuggerContext);
+      myDebuggerContext = debuggerContext;
+      mySelectedNodes = selectedNodes;
+      myWatchPanel = watchPanel;
+    }
+
+    public void threadAction() {
+      for (final DebuggerTreeNodeImpl node : mySelectedNodes) {
+        final NodeDescriptorImpl descriptor = node.getDescriptor();
+        final Project project = myDebuggerContext.getDebuggerSession().getProject();
+        try {
+          final TextWithImports expression = DebuggerTreeNodeExpression.createEvaluationText(node, myDebuggerContext);
+          if (expression != null) {
+            DebuggerInvocationUtil.swingInvokeLater(project, new Runnable() {
+              public void run() {
+                doAddWatch(myWatchPanel, expression, descriptor);
+              }
+            });
+          }
+        }
+        catch (final EvaluateException e) {
+          DebuggerInvocationUtil.swingInvokeLater(project, new Runnable() {
+            public void run() {
+              Messages.showErrorDialog(project, e.getMessage(), ActionsBundle.actionText(XDebuggerActions.ADD_TO_WATCH));
+            }
+          });
+        }
+      }
+    }
+
+    protected void commandCancelled() {
+      DebuggerInvocationUtil.swingInvokeLater(myDebuggerContext.getProject(), new Runnable() {
+        public void run() {
+          for (DebuggerTreeNodeImpl node : mySelectedNodes) {
+            final NodeDescriptorImpl descriptor = node.getDescriptor();
+            if (descriptor instanceof WatchItemDescriptor) {
+              final TextWithImports expression = ((WatchItemDescriptor)descriptor).getEvaluationText();
+              if (expression != null) {
+                doAddWatch(myWatchPanel, expression, descriptor);
+              }
+            }
+          }
+        }
+      });
+    }
+
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/AdjustArrayRangeAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/AdjustArrayRangeAction.java
new file mode 100644
index 0000000..bb74b8e
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/AdjustArrayRangeAction.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.settings.ArrayRendererConfigurable;
+import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
+import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl;
+import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl;
+import com.intellij.debugger.ui.tree.render.*;
+import com.intellij.ide.actions.ShowSettingsUtilImpl;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.options.Configurable;
+import com.intellij.openapi.options.ex.SingleConfigurableEditor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
+import org.jetbrains.annotations.Nullable;
+
+public class AdjustArrayRangeAction extends DebuggerAction {
+  public void actionPerformed(AnActionEvent e) {
+    DebuggerContextImpl debuggerContext = DebuggerAction.getDebuggerContext(e.getDataContext());
+    if(debuggerContext == null) {
+      return;
+    }
+
+    DebugProcessImpl debugProcess = debuggerContext.getDebugProcess();
+    if(debugProcess == null) {
+      return;
+    }
+
+    final Project project = debuggerContext.getProject();
+
+    final DebuggerTreeNodeImpl selectedNode = getSelectedNode(e.getDataContext());
+    if (selectedNode == null) {
+      return;
+    }
+    NodeDescriptorImpl descriptor = selectedNode.getDescriptor();
+    if(!(descriptor instanceof ValueDescriptorImpl /*&& ((ValueDescriptorImpl)descriptor).isArray()*/)) {
+      return;
+    }
+
+    final ArrayRenderer renderer = getArrayRenderer((ValueDescriptorImpl)descriptor)/*(ArrayRenderer)((ValueDescriptorImpl)selectedNode.getDescriptor()).getLastRenderer()*/;
+    if (renderer == null) {
+      return;
+    }
+
+    String title = createNodeTitle("", selectedNode);
+    String label = selectedNode.toString();
+    int index = label.indexOf('=');
+    if (index > 0) {
+      title = title + " " + label.substring(index);
+    }
+    final ArrayRenderer clonedRenderer = renderer.clone();
+    final NamedArrayConfigurable configurable = new NamedArrayConfigurable(title, clonedRenderer);
+    SingleConfigurableEditor editor = new SingleConfigurableEditor(project, configurable,
+                                                                   ShowSettingsUtilImpl.createDimensionKey(configurable), false);
+    editor.show();
+
+    if(editor.getExitCode() == DialogWrapper.OK_EXIT_CODE) {
+      debugProcess.getManagerThread().schedule(new SuspendContextCommandImpl(debuggerContext.getSuspendContext()) {
+          public void contextAction() throws Exception {
+            final ValueDescriptorImpl nodeDescriptor = (ValueDescriptorImpl)selectedNode.getDescriptor();
+            final Renderer lastRenderer = nodeDescriptor.getLastRenderer();
+            if (lastRenderer instanceof ArrayRenderer) {
+              selectedNode.setRenderer(clonedRenderer);
+            }
+            else if (lastRenderer instanceof CompoundNodeRenderer) {
+              final CompoundNodeRenderer compoundRenderer = (CompoundNodeRenderer)lastRenderer;
+              final ChildrenRenderer childrenRenderer = compoundRenderer.getChildrenRenderer();
+              if (childrenRenderer instanceof ExpressionChildrenRenderer) {
+                ExpressionChildrenRenderer.setPreferableChildrenRenderer(nodeDescriptor, clonedRenderer);
+                selectedNode.calcRepresentation();
+              }
+            }
+          }
+        });
+    }
+  }
+
+  public void update(AnActionEvent e) {
+    boolean enable = false;
+    DebuggerTreeNodeImpl selectedNode = getSelectedNode(e.getDataContext());
+    if(selectedNode != null) {
+      NodeDescriptorImpl descriptor = selectedNode.getDescriptor();
+      enable = descriptor instanceof ValueDescriptorImpl && getArrayRenderer((ValueDescriptorImpl)descriptor) != null;
+    }
+    e.getPresentation().setVisible(enable);
+  }
+
+  @Nullable
+  private static ArrayRenderer getArrayRenderer(ValueDescriptorImpl descriptor) {
+    final Renderer lastRenderer = descriptor.getLastRenderer();
+    if (lastRenderer instanceof ArrayRenderer) {
+      return (ArrayRenderer)lastRenderer;
+    }
+    if (lastRenderer instanceof CompoundNodeRenderer && ((CompoundNodeRenderer)lastRenderer).getChildrenRenderer() instanceof ExpressionChildrenRenderer) {
+      final NodeRenderer lastChildrenRenderer = ExpressionChildrenRenderer.getLastChildrenRenderer(descriptor);
+      if (lastChildrenRenderer instanceof ArrayRenderer) {
+        return (ArrayRenderer)lastChildrenRenderer;
+      }
+    }
+    return null;
+  }
+
+  private static String createNodeTitle(String prefix, DebuggerTreeNodeImpl node) {
+    if (node != null) {
+      DebuggerTreeNodeImpl parent = node.getParent();
+      NodeDescriptorImpl descriptor = parent.getDescriptor();
+      if (descriptor instanceof ValueDescriptorImpl && ((ValueDescriptorImpl)descriptor).isArray()) {
+        int index = parent.getIndex(node);
+        return createNodeTitle(prefix, parent) + "[" + index + "]";
+      }
+      String name = (node.getDescriptor() != null)? node.getDescriptor().getName() : null;
+      return (name != null)? prefix + " " + name : prefix;
+    }
+    return prefix;
+  }
+
+  private static class NamedArrayConfigurable extends ArrayRendererConfigurable implements Configurable {
+    private final String myTitle;
+
+    public NamedArrayConfigurable(String title, ArrayRenderer renderer) {
+      super(renderer);
+      myTitle = title;
+    }
+
+    public String getDisplayName() {
+      return myTitle;
+    }
+
+    public String getHelpTopic() {
+      return null;
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/AutoRendererAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/AutoRendererAction.java
new file mode 100644
index 0000000..1891a77
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/AutoRendererAction.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.debugger.engine.events.DebuggerContextCommandImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
+import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl;
+import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+
+public class AutoRendererAction extends AnAction{
+  public void actionPerformed(AnActionEvent e) {
+    final DebuggerContextImpl debuggerContext = DebuggerAction.getDebuggerContext(e.getDataContext());
+    final DebuggerTreeNodeImpl[] selectedNodes = DebuggerAction.getSelectedNodes(e.getDataContext());
+
+    if(debuggerContext != null && debuggerContext.getDebugProcess() != null) {
+      debuggerContext.getDebugProcess().getManagerThread().schedule(new DebuggerContextCommandImpl(debuggerContext) {
+          public void threadAction() {
+            for (int i = 0; i < selectedNodes.length; i++) {
+              DebuggerTreeNodeImpl selectedNode = selectedNodes[i];
+              NodeDescriptorImpl descriptor = selectedNode.getDescriptor();
+              if (descriptor instanceof ValueDescriptorImpl) {
+                ((ValueDescriptorImpl) descriptor).setRenderer(null);
+                selectedNode.calcRepresentation();
+              }
+            }
+          }
+        });
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/BaseValueAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/BaseValueAction.java
new file mode 100644
index 0000000..bd0373a
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/BaseValueAction.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * @author max
+ */
+package com.intellij.debugger.actions;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerInvocationUtil;
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
+import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl;
+import com.intellij.debugger.ui.tree.ValueDescriptor;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.actionSystem.PlatformDataKeys;
+import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.progress.util.ProgressWindowWithNotification;
+import com.intellij.openapi.project.Project;
+import com.sun.jdi.Value;
+import org.jetbrains.annotations.Nullable;
+
+/*
+ * @author Jeka
+ */
+public abstract class BaseValueAction extends DebuggerAction {
+
+  public void actionPerformed(AnActionEvent e) {
+    final DataContext actionContext = e.getDataContext();
+    final DebuggerTreeNodeImpl node = getSelectedNode(actionContext);
+    final Value value = getValue(node);
+    if (value == null) {
+      return;
+    }
+    final Project project = PlatformDataKeys.PROJECT.getData(actionContext);
+    final DebuggerManagerEx debuggerManager = DebuggerManagerEx.getInstanceEx(project);
+    if(debuggerManager == null) {
+      return;
+    }
+    final DebuggerContextImpl debuggerContext = debuggerManager.getContext();
+    if (debuggerContext == null || debuggerContext.getDebuggerSession() == null) {
+      return;
+    }
+
+    final ProgressWindowWithNotification progressWindow = new ProgressWindowWithNotification(true, project);
+    SuspendContextCommandImpl getTextCommand = new SuspendContextCommandImpl(debuggerContext.getSuspendContext()) {
+      public Priority getPriority() {
+        return Priority.HIGH;
+      }
+
+      public void contextAction() throws Exception {
+        //noinspection HardCodedStringLiteral
+        progressWindow.setText(DebuggerBundle.message("progress.evaluating", "toString()"));
+
+        final String valueAsString = DebuggerUtilsEx.getValueOrErrorAsString(debuggerContext.createEvaluationContext(), value);
+
+        if (progressWindow.isCanceled()) {
+          return;
+        }
+
+        DebuggerInvocationUtil.swingInvokeLater(project, new Runnable() {
+          public void run() {
+            String text = valueAsString;
+            if (text == null) {
+              text = "";
+            }
+            processText(project, text, node, debuggerContext);
+          }
+        });
+      }
+    };
+    progressWindow.setTitle(DebuggerBundle.message("title.evaluating"));
+    debuggerContext.getDebugProcess().getManagerThread().startProgress(getTextCommand, progressWindow);
+  }
+
+  protected abstract void processText(final Project project, String text, DebuggerTreeNodeImpl node, DebuggerContextImpl debuggerContext);
+
+  public void update(AnActionEvent e) {
+    Presentation presentation = e.getPresentation();
+    Value value = getValue(getSelectedNode(e.getDataContext()));
+    presentation.setEnabled(value != null);
+    presentation.setVisible(value != null);
+  }
+
+  @Nullable
+  private static Value getValue(final DebuggerTreeNodeImpl node) {
+    if (node == null) {
+      return null;
+    }
+    NodeDescriptorImpl descriptor = node.getDescriptor();
+    if (!(descriptor instanceof ValueDescriptor)) {
+      return null;
+    }
+    return ((ValueDescriptor)descriptor).getValue();
+  }
+}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/CompareValueWithClipboardAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/CompareValueWithClipboardAction.java
new file mode 100644
index 0000000..0a4f2a3
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/CompareValueWithClipboardAction.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2000-2012 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.debugger.actions;
+
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
+import com.intellij.openapi.diff.DiffManager;
+import com.intellij.openapi.diff.actions.ClipboardVsValueContents;
+import com.intellij.openapi.project.Project;
+
+/**
+ * @author Jeka
+ */
+public class CompareValueWithClipboardAction extends BaseValueAction {
+  protected void processText(final Project project, final String text, DebuggerTreeNodeImpl node, DebuggerContextImpl debuggerContext) {
+    DiffManager.getInstance().getDiffTool().show(new ClipboardVsValueContents(text, project));
+  }
+}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/CopyValueAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/CopyValueAction.java
new file mode 100644
index 0000000..2565665
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/CopyValueAction.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
+import com.intellij.openapi.ide.CopyPasteManager;
+import com.intellij.openapi.project.Project;
+
+import java.awt.datatransfer.StringSelection;
+
+/*
+ * @author Jeka
+ */
+public class CopyValueAction extends BaseValueAction {
+  protected void processText(final Project project, final String text, DebuggerTreeNodeImpl node, DebuggerContextImpl debuggerContext) {
+    CopyPasteManager.getInstance().setContents(new StringSelection(text));
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/CustomizeContextViewAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/CustomizeContextViewAction.java
new file mode 100644
index 0000000..4be7776
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/CustomizeContextViewAction.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.settings.DebuggerDataViewsConfigurable;
+import com.intellij.debugger.settings.NodeRendererSettings;
+import com.intellij.debugger.settings.UserRenderersConfigurable;
+import com.intellij.debugger.ui.impl.FrameVariablesTree;
+import com.intellij.debugger.ui.impl.watch.DebuggerTree;
+import com.intellij.idea.ActionsBundle;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.PlatformDataKeys;
+import com.intellij.openapi.options.CompositeConfigurable;
+import com.intellij.openapi.options.Configurable;
+import com.intellij.openapi.options.ConfigurationException;
+import com.intellij.openapi.options.TabbedConfigurable;
+import com.intellij.openapi.options.ex.SingleConfigurableEditor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Disposer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * User: lex
+ * Date: Sep 26, 2003
+ * Time: 4:39:53 PM
+ */
+public class CustomizeContextViewAction extends DebuggerAction{
+  public void actionPerformed(AnActionEvent e) {
+    final Project project = PlatformDataKeys.PROJECT.getData(e.getDataContext());
+
+    Disposable disposable = Disposer.newDisposable();
+    final CompositeConfigurable configurable = new TabbedConfigurable(disposable) {
+      protected List<Configurable> createConfigurables() {
+        ArrayList<Configurable> array = new ArrayList<Configurable>();
+        array.add(new DebuggerDataViewsConfigurable(project));
+        array.add(new UserRenderersConfigurable(project));
+        return array;
+      }
+
+      public void apply() throws ConfigurationException {
+        super.apply();
+        NodeRendererSettings.getInstance().fireRenderersChanged();
+      }
+
+      public String getDisplayName() {
+        return DebuggerBundle.message("title.customize.data.views");
+      }
+
+      public String getHelpTopic() {
+        return null;
+      }
+    };
+
+    SingleConfigurableEditor editor = new SingleConfigurableEditor(project, configurable);
+    Disposer.register(editor.getDisposable(), disposable);
+    editor.show();
+  }
+
+  public void update(AnActionEvent e) {
+    DebuggerTree tree = getTree(e.getDataContext());
+    e.getPresentation().setVisible(tree instanceof FrameVariablesTree);
+    e.getPresentation().setText(ActionsBundle.actionText(DebuggerActions.CUSTOMIZE_VIEWS));
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/CustomizeThreadsViewAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/CustomizeThreadsViewAction.java
new file mode 100644
index 0000000..1681d68
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/CustomizeThreadsViewAction.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.debugger.settings.ThreadsViewConfigurable;
+import com.intellij.debugger.settings.ThreadsViewSettings;
+import com.intellij.idea.ActionsBundle;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.PlatformDataKeys;
+import com.intellij.openapi.options.ex.SingleConfigurableEditor;
+import com.intellij.openapi.project.Project;
+
+/**
+ * User: lex
+ * Date: Sep 26, 2003
+ * Time: 4:40:12 PM
+ */
+public class CustomizeThreadsViewAction extends DebuggerAction {
+  public void actionPerformed(AnActionEvent e) {
+    Project project = PlatformDataKeys.PROJECT.getData(e.getDataContext());
+    final SingleConfigurableEditor editor = new SingleConfigurableEditor(project, new ThreadsViewConfigurable(ThreadsViewSettings.getInstance()));
+    editor.show();
+  }
+
+  public void update(AnActionEvent e) {
+    e.getPresentation().setVisible(true);
+    e.getPresentation().setText(ActionsBundle.actionText(DebuggerActions.CUSTOMIZE_THREADS_VIEW));
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/DebuggerAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/DebuggerAction.java
new file mode 100644
index 0000000..8aebe9e
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/DebuggerAction.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class DebuggerAction
+ * @author Jeka
+ */
+package com.intellij.debugger.actions;
+
+
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerStateManager;
+import com.intellij.debugger.ui.impl.DebuggerTreePanel;
+import com.intellij.debugger.ui.impl.watch.DebuggerTree;
+import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
+import com.intellij.ide.DataManager;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.project.Project;
+import com.intellij.ui.DoubleClickListener;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import javax.swing.tree.TreePath;
+import java.awt.event.MouseEvent;
+import java.util.ArrayList;
+import java.util.List;
+
+public abstract class DebuggerAction extends AnAction {
+  private static final DebuggerTreeNodeImpl[] EMPTY_TREE_NODE_ARRAY = new DebuggerTreeNodeImpl[0];
+
+  @Nullable
+  public static DebuggerTree getTree(DataContext dataContext){
+    return DebuggerTree.DATA_KEY.getData(dataContext);
+  }
+
+  @Nullable
+  public static DebuggerTreePanel getPanel(DataContext dataContext){
+    return DebuggerTreePanel.DATA_KEY.getData(dataContext);
+  }
+
+  @Nullable
+  public static DebuggerTreeNodeImpl getSelectedNode(DataContext dataContext) {
+    DebuggerTree tree = getTree(dataContext);
+    if(tree == null) return null;
+
+    if (tree.getSelectionCount() != 1) {
+      return null;
+    }
+    TreePath path = tree.getSelectionPath();
+    if (path == null) {
+      return null;
+    }
+    Object component = path.getLastPathComponent();
+    if (!(component instanceof DebuggerTreeNodeImpl)) {
+      return null;
+    }
+    return (DebuggerTreeNodeImpl)component;
+  }
+
+  @Nullable
+  public static DebuggerTreeNodeImpl[] getSelectedNodes(DataContext dataContext) {
+    DebuggerTree tree = getTree(dataContext);
+    if(tree == null) return null;
+    TreePath[] paths = tree.getSelectionPaths();
+    if (paths == null || paths.length == 0) {
+      return EMPTY_TREE_NODE_ARRAY;
+    }
+    List<DebuggerTreeNodeImpl> nodes = new ArrayList<DebuggerTreeNodeImpl>(paths.length);
+    for (TreePath path : paths) {
+      Object component = path.getLastPathComponent();
+      if (component instanceof DebuggerTreeNodeImpl) {
+        nodes.add((DebuggerTreeNodeImpl) component);
+      }
+    }
+    return nodes.toArray(new DebuggerTreeNodeImpl[nodes.size()]);
+  }
+
+  public static DebuggerContextImpl getDebuggerContext(DataContext dataContext) {
+    DebuggerTreePanel panel = getPanel(dataContext);
+    if(panel != null) {
+      return panel.getContext();
+    } else {
+      Project project = PlatformDataKeys.PROJECT.getData(dataContext);
+      return project != null ? (DebuggerManagerEx.getInstanceEx(project)).getContext() : DebuggerContextImpl.EMPTY_CONTEXT;
+    }
+  }
+
+  @Nullable
+  public static DebuggerStateManager getContextManager(DataContext dataContext) {
+    DebuggerTreePanel panel = getPanel(dataContext);
+    return panel == null ? null : panel.getContextManager();
+  }
+
+  public static boolean isContextView(AnActionEvent e) {
+    return DebuggerActions.EVALUATION_DIALOG_POPUP.equals(e.getPlace()) ||
+           DebuggerActions.FRAME_PANEL_POPUP.equals(e.getPlace()) ||
+           DebuggerActions.WATCH_PANEL_POPUP.equals(e.getPlace()) ||
+           DebuggerActions.INSPECT_PANEL_POPUP.equals(e.getPlace());
+  }
+
+  public static Disposable installEditAction(final JTree tree, String actionName) {
+    final DoubleClickListener listener = new DoubleClickListener() {
+      @Override
+      protected boolean onDoubleClick(MouseEvent e) {
+        if (tree.getPathForLocation(e.getX(), e.getY()) == null) return false;
+        DataContext dataContext = DataManager.getInstance().getDataContext(tree);
+        GotoFrameSourceAction.doAction(dataContext);
+        return true;
+      }
+    };
+    listener.installOn(tree);
+
+    final AnAction action = ActionManager.getInstance().getAction(actionName);
+    action.registerCustomShortcutSet(CommonShortcuts.getEditSource(), tree);
+
+    return new Disposable() {
+      public void dispose() {
+        listener.uninstall(tree);
+        action.unregisterCustomShortcutSet(tree);
+      }
+    };
+  }
+
+  public static boolean isFirstStart(final AnActionEvent event) {
+    //noinspection HardCodedStringLiteral
+    String key = "initalized";
+    if(event.getPresentation().getClientProperty(key) != null) return false;
+
+    event.getPresentation().putClientProperty(key, key);
+    return true;
+  }
+
+  public static void enableAction(final AnActionEvent event, final boolean enable) {
+    SwingUtilities.invokeLater(new Runnable() {
+      public void run() {
+        event.getPresentation().setEnabled(enable);
+        event.getPresentation().setVisible(true);
+      }
+    });
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/DebuggerActions.java b/java/debugger/impl/src/com/intellij/debugger/actions/DebuggerActions.java
new file mode 100644
index 0000000..ca323d4
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/DebuggerActions.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Interface DebuggerActions
+ * @author Jeka
+ */
+package com.intellij.debugger.actions;
+
+import com.intellij.debugger.ui.impl.DebuggerTreePanel;
+import com.intellij.debugger.ui.impl.watch.DebuggerTree;
+import com.intellij.xdebugger.impl.actions.XDebuggerActions;
+import org.jetbrains.annotations.NonNls;
+
+public interface DebuggerActions extends XDebuggerActions {
+  @NonNls String POP_FRAME = "Debugger.PopFrame";
+  @NonNls String EVALUATION_DIALOG_POPUP = "Debugger.EvaluationDialogPopup";
+  @NonNls String FRAME_PANEL_POPUP = "Debugger.FramePanelPopup";
+  @NonNls String INSPECT_PANEL_POPUP = "Debugger.InspectPanelPopup";
+  @NonNls String THREADS_PANEL_POPUP = "Debugger.ThreadsPanelPopup";
+  @NonNls String WATCH_PANEL_POPUP = "Debugger.WatchesPanelPopup";
+  @Deprecated @NonNls String DEBUGGER_TREE = DebuggerTree.DATA_KEY.getName();
+  @Deprecated @NonNls String DEBUGGER_TREE_PANEL = DebuggerTreePanel.DATA_KEY.getName();
+  @NonNls String REMOVE_WATCH = "Debugger.RemoveWatch";
+  @NonNls String NEW_WATCH = "Debugger.NewWatch";
+  @NonNls String EDIT_WATCH = "Debugger.EditWatch";
+  @NonNls String COPY_VALUE = "Debugger.CopyValue";
+  @NonNls String SET_VALUE = "Debugger.SetValue";
+  @NonNls String EDIT_FRAME_SOURCE = "Debugger.EditFrameSource";
+  @NonNls String EDIT_NODE_SOURCE = "Debugger.EditNodeSource";
+  @NonNls String REPRESENTATION_LIST = "Debugger.Representation";
+  @NonNls String CUSTOMIZE_VIEWS = "Debugger.CustomizeContextView";
+  @NonNls String CUSTOMIZE_THREADS_VIEW = "Debugger.CustomizeThreadsView";
+  @NonNls String INSPECT = "Debugger.Inspect";
+  @NonNls String EXPORT_THREADS = "ExportThreads";
+  @NonNls String DUMP_THREADS = "DumpThreads";
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/DebuggerKeymapExtension.java b/java/debugger/impl/src/com/intellij/debugger/actions/DebuggerKeymapExtension.java
new file mode 100644
index 0000000..c200cb1
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/DebuggerKeymapExtension.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.keymap.KeyMapBundle;
+import com.intellij.openapi.keymap.KeymapExtension;
+import com.intellij.openapi.keymap.KeymapGroup;
+import com.intellij.openapi.keymap.impl.ui.Group;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Condition;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * @author yole
+ */
+public class DebuggerKeymapExtension implements KeymapExtension {
+  public KeymapGroup createGroup(final Condition<AnAction> filtered, final Project project) {
+    ActionManager actionManager = ActionManager.getInstance();
+    DefaultActionGroup debuggerGroup = (DefaultActionGroup)actionManager.getActionOrStub(IdeActions.GROUP_DEBUGGER);
+    AnAction[] debuggerActions = debuggerGroup.getChildActionsOrStubs();
+
+    ArrayList<String> ids = new ArrayList<String>();
+    for (AnAction debuggerAction : debuggerActions) {
+      String actionId = debuggerAction instanceof ActionStub ? ((ActionStub)debuggerAction).getId() : actionManager.getId(debuggerAction);
+      if (filtered == null || filtered.value(debuggerAction)) {
+        ids.add(actionId);
+      }
+    }
+
+    Collections.sort(ids);
+    Group group = new Group(KeyMapBundle.message("debugger.actions.group.title"), IdeActions.GROUP_DEBUGGER, null);
+    for (String id : ids) {
+      group.addActionId(id);
+    }
+
+    return group;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/EditFrameSourceAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/EditFrameSourceAction.java
new file mode 100644
index 0000000..ba02df4
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/EditFrameSourceAction.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.openapi.actionSystem.ActionManager;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.IdeActions;
+
+/**
+ * @author lex
+ */
+public class EditFrameSourceAction extends GotoFrameSourceAction{
+  public void update(AnActionEvent e) {
+    super.update(e);
+    e.getPresentation().setText(ActionManager.getInstance().getAction(IdeActions.ACTION_EDIT_SOURCE).getTemplatePresentation().getText());
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/EditSourceAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/EditSourceAction.java
new file mode 100644
index 0000000..b009370
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/EditSourceAction.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.debugger.DebuggerInvocationUtil;
+import com.intellij.debugger.SourcePosition;
+import com.intellij.debugger.engine.evaluation.expression.Modifier;
+import com.intellij.debugger.engine.events.DebuggerContextCommandImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.debugger.ui.impl.watch.*;
+import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Computable;
+
+public class EditSourceAction extends DebuggerAction{
+  public void actionPerformed(AnActionEvent e) {
+    final Project project = PlatformDataKeys.PROJECT.getData(e.getDataContext());
+
+    if(project == null) return;
+
+    final DebuggerContextImpl debuggerContext = getDebuggerContext(e.getDataContext());
+    final DebuggerTreeNodeImpl selectedNode = getSelectedNode(e.getDataContext());
+    if(debuggerContext != null && selectedNode != null) {
+      debuggerContext.getDebugProcess().getManagerThread().schedule(new DebuggerContextCommandImpl(debuggerContext) {
+          public void threadAction() {
+            final SourcePosition sourcePosition = getSourcePosition(selectedNode, debuggerContext);
+            if (sourcePosition != null) {
+              sourcePosition.navigate(true);
+            }
+          }
+        });
+    }
+  }
+
+  private SourcePosition getSourcePosition(DebuggerTreeNodeImpl selectedNode, DebuggerContextImpl debuggerContext) {
+    DebuggerTreeNodeImpl node = selectedNode;
+    final DebuggerContextImpl context = debuggerContext;
+
+    if(node == null) return null;
+    if(context == null) return null;
+
+    final Project project = context.getProject();
+
+    final DebuggerSession debuggerSession = context.getDebuggerSession();
+
+    if(debuggerSession == null) return null;
+
+    NodeDescriptorImpl nodeDescriptor = node.getDescriptor();
+    if(nodeDescriptor instanceof WatchItemDescriptor) {
+      Modifier modifier = ((WatchItemDescriptor)nodeDescriptor).getModifier();
+
+      if(modifier == null) return null;
+
+      nodeDescriptor = (NodeDescriptorImpl)modifier.getInspectItem(project);
+    }
+
+    final NodeDescriptorImpl nodeDescriptor1 = nodeDescriptor;
+    return ApplicationManager.getApplication().runReadAction(new Computable<SourcePosition>() {
+      public SourcePosition compute() {
+        if (nodeDescriptor1 instanceof FieldDescriptorImpl && debuggerSession != null) {
+          return ((FieldDescriptorImpl)nodeDescriptor1).getSourcePosition(project, context);
+        }
+        if (nodeDescriptor1 instanceof LocalVariableDescriptorImpl && debuggerSession != null) {
+          return ((LocalVariableDescriptorImpl)nodeDescriptor1).getSourcePosition(project, context);
+        }
+        return null;
+      }
+    });
+  }
+
+  public void update(AnActionEvent e) {
+    final Project project = PlatformDataKeys.PROJECT.getData(e.getDataContext());
+
+    final DebuggerContextImpl debuggerContext = getDebuggerContext(e.getDataContext());
+    final DebuggerTreeNodeImpl node = getSelectedNode(e.getDataContext());
+
+    final Presentation presentation = e.getPresentation();
+
+    presentation.setEnabled(true);
+
+    //if user used shortcut actionPerformed is called immediately after update
+    //we not disable presentation here to allow actionPerform work
+    DebuggerInvocationUtil.invokeLater(project, new Runnable() {
+      public void run() {
+        presentation.setEnabled(false);
+      }
+    });
+
+    if(debuggerContext != null && debuggerContext.getDebugProcess() != null) {
+      debuggerContext.getDebugProcess().getManagerThread().schedule(new DebuggerContextCommandImpl(debuggerContext) {
+        public void threadAction() {
+          final SourcePosition position = getSourcePosition(node, debuggerContext);
+          if (position != null) {
+            DebuggerInvocationUtil.swingInvokeLater(project, new Runnable() {
+              public void run() {
+                presentation.setEnabled(true);
+              }
+            });
+          }
+        }
+      });
+    }
+
+    e.getPresentation().setText(ActionManager.getInstance().getAction(IdeActions.ACTION_EDIT_SOURCE).getTemplatePresentation().getText());
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/EditWatchAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/EditWatchAction.java
new file mode 100644
index 0000000..1654287
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/EditWatchAction.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.debugger.ui.DebuggerPanelsManager;
+import com.intellij.debugger.ui.impl.MainWatchPanel;
+import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
+import com.intellij.debugger.ui.impl.watch.WatchItemDescriptor;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.PlatformDataKeys;
+import com.intellij.openapi.project.Project;
+
+/**
+ * User: lex
+ * Date: Sep 26, 2003
+ * Time: 8:34:01 PM
+ */
+public class EditWatchAction extends DebuggerAction {
+  public void actionPerformed(final AnActionEvent e) {
+    final DebuggerTreeNodeImpl selectedNode = getSelectedNode(e.getDataContext());
+    if(selectedNode == null || !(selectedNode.getDescriptor() instanceof WatchItemDescriptor)) return;
+
+    Project project = PlatformDataKeys.PROJECT.getData(e.getDataContext());
+
+    MainWatchPanel watchPanel = DebuggerPanelsManager.getInstance(project).getWatchPanel();
+    if(watchPanel != null) {
+      watchPanel.editNode(selectedNode);
+    }
+  }
+
+  public void update(AnActionEvent e) {
+    final DebuggerTreeNodeImpl selectedNode = getSelectedNode(e.getDataContext());
+
+    e.getPresentation().setVisible(selectedNode != null && selectedNode.getDescriptor() instanceof WatchItemDescriptor);
+  }
+
+};
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/EvaluateActionHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/EvaluateActionHandler.java
new file mode 100644
index 0000000..22694cb
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/EvaluateActionHandler.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class EvaluateAction
+ * @author Jeka
+ */
+package com.intellij.debugger.actions;
+
+import com.intellij.debugger.DebuggerInvocationUtil;
+import com.intellij.debugger.engine.evaluation.CodeFragmentKind;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.debugger.engine.evaluation.TextWithImportsImpl;
+import com.intellij.debugger.engine.events.DebuggerContextCommandImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.settings.DebuggerSettings;
+import com.intellij.debugger.ui.ExpressionEvaluationDialog;
+import com.intellij.debugger.ui.StatementEvaluationDialog;
+import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeExpression;
+import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
+import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl;
+import com.intellij.debugger.ui.impl.watch.WatchItemDescriptor;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.actionSystem.DataKeys;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.openapi.ui.Messages;
+import com.intellij.xdebugger.impl.actions.DebuggerActionHandler;
+import org.jetbrains.annotations.NotNull;
+
+public class EvaluateActionHandler extends DebuggerActionHandler {
+  public boolean isEnabled(@NotNull final Project project, final AnActionEvent event) {
+    DebuggerContextImpl context = DebuggerAction.getDebuggerContext(event.getDataContext());
+
+    if(context != null) {
+      DebuggerSession debuggerSession = context.getDebuggerSession();
+      return debuggerSession != null && debuggerSession.isPaused();
+    }
+
+    return false;
+  }
+
+  public void perform(@NotNull final Project project, final AnActionEvent event) {
+    final DataContext dataContext = event.getDataContext();
+    final DebuggerContextImpl context = DebuggerAction.getDebuggerContext(dataContext);
+
+    if(context == null) {
+      return;
+    }
+
+    final Editor editor = event.getData(DataKeys.EDITOR);
+
+    TextWithImports editorText = DebuggerUtilsEx.getEditorText(editor);
+    if (editorText == null) {
+      final DebuggerTreeNodeImpl selectedNode = DebuggerAction.getSelectedNode(dataContext);
+      final String actionName = event.getPresentation().getText();
+
+      if (selectedNode != null && selectedNode.getDescriptor() instanceof ValueDescriptorImpl) {
+        context.getDebugProcess().getManagerThread().schedule(new DebuggerContextCommandImpl(context) {
+          public void threadAction() {
+            try {
+              final TextWithImports evaluationText = DebuggerTreeNodeExpression.createEvaluationText(selectedNode, context);
+              DebuggerInvocationUtil.swingInvokeLater(project, new Runnable() {
+                public void run() {
+                  showEvaluationDialog(project, evaluationText);
+                }
+              });
+            }
+            catch (final EvaluateException e1) {
+              DebuggerInvocationUtil.swingInvokeLater(project, new Runnable() {
+                public void run() {
+                  Messages.showErrorDialog(project, e1.getMessage(), actionName);
+                }
+              });
+            }
+          }
+
+          protected void commandCancelled() {
+            DebuggerInvocationUtil.swingInvokeLater(project, new Runnable() {
+              public void run() {
+                if(selectedNode.getDescriptor() instanceof WatchItemDescriptor) {
+                  try {
+                    TextWithImports editorText = DebuggerTreeNodeExpression.createEvaluationText(selectedNode, context);
+                    showEvaluationDialog(project, editorText);
+                  }
+                  catch (EvaluateException e1) {
+                    Messages.showErrorDialog(project, e1.getMessage(), actionName);
+                  }
+                }
+              }
+            });
+          }
+        });
+        return;
+      }
+    }
+
+    showEvaluationDialog(project, editorText);
+  }
+
+  public static void showEvaluationDialog(Project project, TextWithImports defaultExpression, String dialogType) {
+    if(defaultExpression == null) {
+      defaultExpression = new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, "");
+    }
+
+    CodeFragmentKind kind = DebuggerSettings.EVALUATE_FRAGMENT.equals(dialogType) ? CodeFragmentKind.CODE_BLOCK : CodeFragmentKind.EXPRESSION;
+
+    DebuggerSettings.getInstance().EVALUATION_DIALOG_TYPE = dialogType;
+    TextWithImportsImpl text = new TextWithImportsImpl(kind, defaultExpression.getText(), defaultExpression.getImports(), defaultExpression.getFileType());
+
+    final DialogWrapper dialog;
+    if(DebuggerSettings.EVALUATE_FRAGMENT.equals(dialogType)) {
+      dialog = new StatementEvaluationDialog(project, text);
+    }
+    else {
+      dialog = new ExpressionEvaluationDialog(project, text);
+    }
+
+    dialog.show();
+  }
+
+  public static void showEvaluationDialog(Project project, TextWithImports text) {
+    showEvaluationDialog(project, text, DebuggerSettings.getInstance().EVALUATION_DIALOG_TYPE);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/ExportThreadsAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/ExportThreadsAction.java
new file mode 100644
index 0000000..e7b43d1
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/ExportThreadsAction.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/**
+ * class ExportThreadsAction
+ * @author Jeka
+ */
+package com.intellij.debugger.actions;
+
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.debugger.ui.ExportDialog;
+import com.intellij.idea.ActionsBundle;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.PlatformDataKeys;
+import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.Messages;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.util.SystemProperties;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+
+public class ExportThreadsAction extends AnAction implements AnAction.TransparentUpdate {
+  public void actionPerformed(AnActionEvent e) {
+    Project project = PlatformDataKeys.PROJECT.getData(e.getDataContext());
+    if (project == null) {
+      return;
+    }
+    DebuggerContextImpl context = (DebuggerManagerEx.getInstanceEx(project)).getContext();
+
+    if(context.getDebuggerSession() != null) {
+      String destinationDirectory = "";
+      final VirtualFile baseDir = project.getBaseDir();
+      if (baseDir != null) destinationDirectory = baseDir.getPresentableUrl();
+
+      ExportDialog dialog = new ExportDialog(context.getDebugProcess(),  destinationDirectory);
+      dialog.show();
+      if (dialog.isOK()) {
+        try {
+          File file = new File(dialog.getFilePath());
+          BufferedWriter writer = new BufferedWriter(new FileWriter(file));
+          try {
+            String text = StringUtil.convertLineSeparators(dialog.getTextToSave(), SystemProperties.getLineSeparator());
+            writer.write(text);
+          }
+          finally {
+            writer.close();
+          }
+        }
+        catch (IOException ex) {
+          Messages.showMessageDialog(project, ex.getMessage(), ActionsBundle.actionText(DebuggerActions.EXPORT_THREADS), Messages.getErrorIcon());
+        }
+      }
+    }
+  }
+
+
+
+  public void update(AnActionEvent event){
+    Presentation presentation = event.getPresentation();
+    Project project = PlatformDataKeys.PROJECT.getData(event.getDataContext());
+    if (project == null) {
+      presentation.setEnabled(false);
+      return;
+    }
+    DebuggerSession debuggerSession = (DebuggerManagerEx.getInstanceEx(project)).getContext().getDebuggerSession();
+    presentation.setEnabled(debuggerSession != null && debuggerSession.isPaused());
+  }
+}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/ForceRunToCursorActionHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/ForceRunToCursorActionHandler.java
new file mode 100644
index 0000000..553b5d4
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/ForceRunToCursorActionHandler.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: Sep 12, 2006
+ */
+public class ForceRunToCursorActionHandler extends RunToCursorActionHandler {
+  public ForceRunToCursorActionHandler() {
+    super(true);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/ForceStepIntoActionHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/ForceStepIntoActionHandler.java
new file mode 100644
index 0000000..dc74274
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/ForceStepIntoActionHandler.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.project.Project;
+import org.jetbrains.annotations.NotNull;
+
+public class ForceStepIntoActionHandler extends AbstractSteppingActionHandler {
+  public void perform(@NotNull final Project project, AnActionEvent e) {
+    final DebuggerSession session = getSession(project);
+    if (session != null) {
+      session.stepInto(true, null);
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/ForceStepOverActionHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/ForceStepOverActionHandler.java
new file mode 100644
index 0000000..613fcf0
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/ForceStepOverActionHandler.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.project.Project;
+import org.jetbrains.annotations.NotNull;
+
+public class ForceStepOverActionHandler extends AbstractSteppingActionHandler {
+  public void perform(@NotNull final Project project, AnActionEvent e) {
+    final DebuggerSession session = getSession(project);
+    if (session != null) {
+      session.stepOver(true);
+    }
+  }
+}
+
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/FreezeThreadAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/FreezeThreadAction.java
new file mode 100644
index 0000000..eb6dea3
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/FreezeThreadAction.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
+import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
+import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl;
+import com.intellij.debugger.ui.impl.watch.ThreadDescriptorImpl;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+
+/**
+ * @author lex
+ */
+public class FreezeThreadAction extends DebuggerAction {
+  public void actionPerformed(final AnActionEvent e) {
+    DebuggerTreeNodeImpl[] selectedNode = getSelectedNodes(e.getDataContext());
+    if (selectedNode == null) {
+      return;
+    }
+    final DebuggerContextImpl debuggerContext = getDebuggerContext(e.getDataContext());
+    final DebugProcessImpl debugProcess = debuggerContext.getDebugProcess();
+
+    for (final DebuggerTreeNodeImpl debuggerTreeNode : selectedNode) {
+      ThreadDescriptorImpl threadDescriptor = ((ThreadDescriptorImpl)debuggerTreeNode.getDescriptor());
+      final ThreadReferenceProxyImpl thread = threadDescriptor.getThreadReference();
+
+      if (!threadDescriptor.isFrozen()) {
+        debugProcess.getManagerThread().schedule(new SuspendContextCommandImpl(debuggerContext.getSuspendContext()) {
+          public void contextAction() throws Exception {
+            debugProcess.createFreezeThreadCommand(thread).run();
+            debuggerTreeNode.calcValue();
+          }
+        });
+      }
+    }
+  }
+
+  public void update(AnActionEvent e) {
+    DebuggerTreeNodeImpl[] selectedNode = getSelectedNodes(e.getDataContext());
+    if (selectedNode == null) {
+      return;
+    }
+    DebugProcessImpl debugProcess = getDebuggerContext(e.getDataContext()).getDebugProcess();
+
+    boolean visible = false;
+    if (debugProcess != null) {
+      visible = true;
+      for (DebuggerTreeNodeImpl aSelectedNode : selectedNode) {
+        NodeDescriptorImpl threadDescriptor = aSelectedNode.getDescriptor();
+        if (!(threadDescriptor instanceof ThreadDescriptorImpl) || ((ThreadDescriptorImpl)threadDescriptor).isFrozen()) {
+          visible = false;
+          break;
+        }
+      }
+
+    }
+
+    e.getPresentation().setVisible(visible);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/GotoFrameSourceAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/GotoFrameSourceAction.java
new file mode 100644
index 0000000..e13a0eb
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/GotoFrameSourceAction.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.debugger.impl.DebuggerContextUtil;
+import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
+import com.intellij.debugger.ui.impl.watch.StackFrameDescriptorImpl;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.actionSystem.PlatformDataKeys;
+import com.intellij.openapi.project.Project;
+
+/**
+ * @author lex
+ */
+public abstract class GotoFrameSourceAction extends DebuggerAction{
+  public void actionPerformed(AnActionEvent e) {
+    DataContext dataContext = e.getDataContext();
+    doAction(dataContext);
+  }
+
+  protected static void doAction(DataContext dataContext) {
+    final Project project = PlatformDataKeys.PROJECT.getData(dataContext);
+    if(project == null) return;
+    StackFrameDescriptorImpl stackFrameDescriptor = getStackFrameDescriptor(dataContext);
+    if(stackFrameDescriptor != null) {
+      DebuggerContextUtil.setStackFrame(getContextManager(dataContext), stackFrameDescriptor.getFrameProxy());
+    }
+  }
+
+  public void update(AnActionEvent e) {
+    e.getPresentation().setVisible(getStackFrameDescriptor(e.getDataContext()) != null);
+  }
+
+  private static StackFrameDescriptorImpl getStackFrameDescriptor(DataContext dataContext) {
+    DebuggerTreeNodeImpl selectedNode = getSelectedNode(dataContext);
+    if(selectedNode == null) return null;
+    if(selectedNode.getDescriptor() == null || !(selectedNode.getDescriptor() instanceof StackFrameDescriptorImpl)) return null;
+    return (StackFrameDescriptorImpl)selectedNode.getDescriptor();
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/HotSwapAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/HotSwapAction.java
new file mode 100644
index 0000000..250ae85
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/HotSwapAction.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.debugger.settings.DebuggerSettings;
+import com.intellij.debugger.ui.HotSwapUI;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.actionSystem.PlatformDataKeys;
+import com.intellij.openapi.project.Project;
+
+/**
+ * @author lex
+ */
+public class HotSwapAction extends AnAction{
+
+  public void actionPerformed(AnActionEvent e) {
+    DataContext dataContext = e.getDataContext();
+    Project project = PlatformDataKeys.PROJECT.getData(dataContext);
+    if(project == null) {
+      return;
+    }
+
+    DebuggerManagerEx debuggerManager = DebuggerManagerEx.getInstanceEx(project);
+    DebuggerSession session = debuggerManager.getContext().getDebuggerSession();
+
+    if(session != null && session.isAttached()) {
+      HotSwapUI.getInstance(project).reloadChangedClasses(session, DebuggerSettings.getInstance().COMPILE_BEFORE_HOTSWAP);
+    }
+  }
+
+  public void update(AnActionEvent e) {
+    DataContext dataContext = e.getDataContext();
+    Project project = PlatformDataKeys.PROJECT.getData(dataContext);
+    if(project == null) {
+      e.getPresentation().setEnabled(false);
+      return;
+    }
+
+    DebuggerManagerEx debuggerManager = DebuggerManagerEx.getInstanceEx(project);
+    DebuggerSession session = debuggerManager.getContext().getDebuggerSession();
+
+    e.getPresentation().setEnabled(session != null && session.isAttached() && session.getProcess().canRedefineClasses());
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/InspectAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/InspectAction.java
new file mode 100644
index 0000000..36bc1b7
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/InspectAction.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class InspectAction
+ * @author Jeka
+ */
+package com.intellij.debugger.actions;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerInvocationUtil;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.debugger.engine.evaluation.expression.Modifier;
+import com.intellij.debugger.engine.events.DebuggerContextCommandImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.debugger.impl.DebuggerStateManager;
+import com.intellij.debugger.ui.impl.InspectDialog;
+import com.intellij.debugger.ui.impl.watch.*;
+import com.intellij.idea.ActionsBundle;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.PlatformDataKeys;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.Messages;
+import com.sun.jdi.Field;
+
+public class InspectAction extends DebuggerAction {
+  public void actionPerformed(AnActionEvent e) {
+    final Project project = PlatformDataKeys.PROJECT.getData(e.getDataContext());
+    final DebuggerTreeNodeImpl node = getSelectedNode(e.getDataContext());
+    if(node == null) return;
+    final NodeDescriptorImpl descriptor = node.getDescriptor();
+    final DebuggerStateManager stateManager = getContextManager(e.getDataContext());
+    if(!(descriptor instanceof ValueDescriptorImpl) || stateManager == null) return;
+    final DebuggerContextImpl context = stateManager.getContext();
+
+    if (!canInspect((ValueDescriptorImpl)descriptor, context)) {
+      return;
+    }
+    context.getDebugProcess().getManagerThread().schedule(new DebuggerContextCommandImpl(context) {
+      public void threadAction() {
+        try {
+          final TextWithImports evaluationText = DebuggerTreeNodeExpression.createEvaluationText(node, context);
+
+          final NodeDescriptorImpl inspectDescriptor;
+          if (descriptor instanceof WatchItemDescriptor) {
+            inspectDescriptor = (NodeDescriptorImpl) ((WatchItemDescriptor) descriptor).getModifier().getInspectItem(project);
+          }
+          else {
+            inspectDescriptor = descriptor;
+          }
+
+          DebuggerInvocationUtil.swingInvokeLater(project, new Runnable() {
+            public void run() {
+              final InspectDialog dialog = new InspectDialog(project, stateManager, ActionsBundle.actionText(DebuggerActions.INSPECT) + " '" + evaluationText + "'", inspectDescriptor);
+              dialog.show();
+            }
+          });
+        }
+        catch (final EvaluateException e1) {
+          DebuggerInvocationUtil.swingInvokeLater(project, new Runnable() {
+            public void run() {
+              Messages.showErrorDialog(project, e1.getMessage(), ActionsBundle.actionText(DebuggerActions.INSPECT));
+            }
+          });
+        }
+      }
+    });
+  }
+
+  private boolean canInspect(ValueDescriptorImpl descriptor, DebuggerContextImpl context) {
+    DebuggerSession session = context.getDebuggerSession();
+    if (session == null || !session.isPaused()) return false;
+
+    boolean isField = descriptor instanceof FieldDescriptorImpl;
+
+    if(descriptor instanceof WatchItemDescriptor) {
+      Modifier modifier = ((WatchItemDescriptor)descriptor).getModifier();
+      if(modifier == null || !modifier.canInspect()) return false;
+      isField = modifier instanceof Field;
+    }
+
+    if (isField) { // check if possible
+      if (!context.getDebugProcess().canWatchFieldModification()) {
+        Messages.showMessageDialog(
+          context.getProject(),
+          DebuggerBundle.message("error.modification.watchpoints.not.supported"),
+          ActionsBundle.actionText(DebuggerActions.INSPECT),
+          Messages.getInformationIcon()
+        );
+        return false;
+      }
+    }
+    return true;
+  }
+
+  public void update(AnActionEvent e) {
+    DebuggerTreeNodeImpl selectedNode = getSelectedNode(e.getDataContext());
+    boolean enabled = false;
+    if(selectedNode != null) {
+      NodeDescriptorImpl descriptor = selectedNode.getDescriptor();
+      if(descriptor != null) {
+        if(descriptor instanceof LocalVariableDescriptorImpl || descriptor instanceof FieldDescriptorImpl || descriptor instanceof ArrayElementDescriptorImpl) {
+          enabled = true;
+        }
+        else if(descriptor instanceof WatchItemDescriptor){
+          Modifier modifier = ((WatchItemDescriptor)descriptor).getModifier();
+          enabled = modifier != null && modifier.canInspect();
+        }
+      }
+    }
+    e.getPresentation().setVisible(enabled);
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/InterruptThreadAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/InterruptThreadAction.java
new file mode 100644
index 0000000..62e861d
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/InterruptThreadAction.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2000-2010 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.debugger.actions;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.events.DebuggerCommandImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
+import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
+import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl;
+import com.intellij.debugger.ui.impl.watch.ThreadDescriptorImpl;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.Presentation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * User: lex
+ * Date: Sep 26, 2003
+ * Time: 7:35:09 PM
+ */
+public class InterruptThreadAction extends DebuggerAction{
+  
+  public void actionPerformed(final AnActionEvent e) {
+    final DebuggerTreeNodeImpl[] nodes = getSelectedNodes(e.getDataContext());
+    if (nodes == null) {
+      return;
+    }
+
+    //noinspection ConstantConditions
+    final List<ThreadReferenceProxyImpl> threadsToInterrupt = new ArrayList<ThreadReferenceProxyImpl>();
+    for (final DebuggerTreeNodeImpl debuggerTreeNode : nodes) {
+      final NodeDescriptorImpl descriptor = debuggerTreeNode.getDescriptor();
+      if (descriptor instanceof ThreadDescriptorImpl) {
+        threadsToInterrupt.add(((ThreadDescriptorImpl)descriptor).getThreadReference());
+      }
+    }
+    
+    if (!threadsToInterrupt.isEmpty()) {
+      final DebuggerContextImpl debuggerContext = getDebuggerContext(e.getDataContext());
+      debuggerContext.getDebugProcess().getManagerThread().schedule(new DebuggerCommandImpl() {
+        protected void action() throws Exception {
+          for (ThreadReferenceProxyImpl thread : threadsToInterrupt) {
+            thread.getThreadReference().interrupt();
+          }
+        }
+      });
+    }
+
+  }
+
+  public void update(AnActionEvent e) {
+    final DebuggerTreeNodeImpl[] selectedNodes = getSelectedNodes(e.getDataContext());
+
+    boolean visible = false;
+    boolean enabled = false;
+
+    if(selectedNodes != null && selectedNodes.length > 0){
+      visible = true;
+      enabled = true;
+      for (DebuggerTreeNodeImpl selectedNode : selectedNodes) {
+        final NodeDescriptorImpl threadDescriptor = selectedNode.getDescriptor();
+        if (!(threadDescriptor instanceof ThreadDescriptorImpl)) {
+          visible = false;
+          break;
+        }
+      }
+      
+      if (visible) {
+        for (DebuggerTreeNodeImpl selectedNode : selectedNodes) {
+          final ThreadDescriptorImpl threadDescriptor = (ThreadDescriptorImpl)selectedNode.getDescriptor();
+          if (threadDescriptor.isFrozen()) {
+            enabled = false;
+            break;
+          }
+        }
+      }
+    }
+    final Presentation presentation = e.getPresentation();
+    presentation.setText(DebuggerBundle.message("action.interrupt.thread.text"));
+    presentation.setVisible(visible);
+    presentation.setEnabled(enabled);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/JavaEditBreakpointActionHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/JavaEditBreakpointActionHandler.java
new file mode 100644
index 0000000..cf03ffc
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/JavaEditBreakpointActionHandler.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2000-2012 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.debugger.actions;
+
+import com.intellij.debugger.ui.breakpoints.BreakpointFactory;
+import com.intellij.debugger.ui.breakpoints.BreakpointPropertiesPanel;
+import com.intellij.debugger.ui.breakpoints.BreakpointWithHighlighter;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.actionSystem.PlatformDataKeys;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.ex.EditorGutterComponentEx;
+import com.intellij.openapi.editor.markup.GutterIconRenderer;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.popup.Balloon;
+import com.intellij.openapi.ui.popup.JBPopup;
+import com.intellij.openapi.ui.popup.JBPopupListener;
+import com.intellij.openapi.ui.popup.LightweightWindowEvent;
+import com.intellij.openapi.util.Key;
+import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.wm.IdeFocusManager;
+import com.intellij.util.ui.UIUtil;
+import com.intellij.xdebugger.impl.actions.EditBreakpointActionHandler;
+import com.intellij.xdebugger.impl.breakpoints.XBreakpointUtil;
+import com.intellij.xdebugger.impl.breakpoints.ui.BreakpointsMasterDetailPopupFactory;
+import com.intellij.xdebugger.impl.ui.DebuggerUIUtil;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import java.awt.*;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: zajac
+ * Date: 04.05.12
+ * Time: 4:10
+ * To change this template use File | Settings | File Templates.
+ */
+public class JavaEditBreakpointActionHandler extends EditBreakpointActionHandler {
+  @Override
+  protected void doShowPopup(final Project project, final EditorGutterComponentEx gutterComponent, final Point whereToShow, final Object breakpoint) {
+    if (!(breakpoint instanceof BreakpointWithHighlighter)) return;
+
+    final BreakpointWithHighlighter javaBreakpoint = (BreakpointWithHighlighter)breakpoint;
+    Key<? extends BreakpointWithHighlighter> category = javaBreakpoint.getCategory();
+
+    final BreakpointFactory[] allFactories = ApplicationManager.getApplication().getExtensions(BreakpointFactory.EXTENSION_POINT_NAME);
+    BreakpointFactory breakpointFactory = null;
+    for (BreakpointFactory factory : allFactories) {
+      if (factory.getBreakpointCategory().equals(category)) {
+        breakpointFactory = factory;
+      }
+    }
+    assert breakpointFactory != null : "can't find factory for breakpoint " + javaBreakpoint;
+
+    final BreakpointPropertiesPanel propertiesPanel = breakpointFactory.createBreakpointPropertiesPanel(project, true);
+    propertiesPanel.initFrom(javaBreakpoint, false);
+
+    final JComponent mainPanel = propertiesPanel.getPanel();
+    final String displayName = javaBreakpoint.getDisplayName();
+
+    final JBPopupListener saveOnClose = new JBPopupListener() {
+      @Override
+      public void beforeShown(LightweightWindowEvent event) {
+      }
+
+      @Override
+      public void onClosed(LightweightWindowEvent event) {
+        propertiesPanel.saveTo(javaBreakpoint, new Runnable() {
+          @Override
+          public void run() {
+          }
+        });
+      }
+    };
+
+    final Runnable showMoreOptions = new Runnable() {
+      @Override
+      public void run() {
+        UIUtil.invokeLaterIfNeeded(new Runnable() {
+          @Override
+          public void run() {
+            final JBPopup popup = BreakpointsMasterDetailPopupFactory.
+              getInstance(project).createPopup(javaBreakpoint);
+            if (popup != null) {
+              popup.showCenteredInCurrentWindow(project);
+            }
+          }
+        });
+      }
+    };
+    final Balloon balloon = DebuggerUIUtil.showBreakpointEditor(project, mainPanel, displayName, whereToShow, gutterComponent, showMoreOptions,
+                                                                breakpoint);
+    balloon.addListener(saveOnClose);
+
+    propertiesPanel.setDelegate(new BreakpointPropertiesPanel.Delegate() {
+      @Override
+      public void showActionsPanel() {
+        propertiesPanel.setActionsPanelVisible(true);
+        balloon.hide();
+        final Balloon newBalloon =
+          DebuggerUIUtil.showBreakpointEditor(project, mainPanel, displayName, whereToShow, gutterComponent, showMoreOptions, breakpoint);
+        newBalloon.addListener(saveOnClose);
+      }
+    });
+
+    ApplicationManager.getApplication().invokeLater(new Runnable() {
+      @Override
+      public void run() {
+        IdeFocusManager.findInstance().requestFocus(mainPanel, true);
+      }
+    });
+  }
+
+  @Override
+  public boolean isEnabled(@NotNull Project project, AnActionEvent event) {
+    DataContext dataContext = event.getDataContext();
+    Editor editor = PlatformDataKeys.EDITOR.getData(dataContext);
+    if (editor == null) {
+      return false;
+    }
+    final Pair<GutterIconRenderer,Object> pair = XBreakpointUtil.findSelectedBreakpoint(project, editor);
+    return pair.first != null && pair.second instanceof BreakpointWithHighlighter;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/JavaMarkObjectActionHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/JavaMarkObjectActionHandler.java
new file mode 100644
index 0000000..dcd0454
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/JavaMarkObjectActionHandler.java
@@ -0,0 +1,273 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.codeInsight.daemon.impl.HighlightInfoType;
+import com.intellij.debugger.engine.DebugProcess;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.DebuggerUtils;
+import com.intellij.debugger.engine.events.DebuggerContextCommandImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.debugger.ui.impl.tree.TreeBuilder;
+import com.intellij.debugger.ui.impl.watch.DebuggerTree;
+import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
+import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl;
+import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl;
+import com.intellij.debugger.ui.tree.ValueDescriptor;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.colors.EditorColorsManager;
+import com.intellij.openapi.editor.markup.TextAttributes;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Comparing;
+import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.Ref;
+import com.intellij.util.containers.HashMap;
+import com.intellij.xdebugger.impl.actions.MarkObjectActionHandler;
+import com.intellij.xdebugger.impl.ui.tree.ValueMarkup;
+import com.sun.jdi.*;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.awt.*;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/*
+ * Class SetValueAction
+ * @author Jeka
+ */
+public class JavaMarkObjectActionHandler extends MarkObjectActionHandler {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.actions.JavaMarkObjectActionHandler");
+  public static final long AUTO_MARKUP_REFERRING_OBJECTS_LIMIT = 100L; // todo: some reasonable limit
+
+  @Override
+  public void perform(@NotNull Project project, AnActionEvent event) {
+    final DebuggerTreeNodeImpl node = DebuggerAction.getSelectedNode(event.getDataContext());
+    if (node == null) {
+      return;
+    }
+    final NodeDescriptorImpl descriptor = node.getDescriptor();
+    if (!(descriptor instanceof ValueDescriptorImpl)) {
+      return;
+    }
+    
+    final DebuggerTree tree = node.getTree();
+    tree.saveState(node);
+    
+    final ValueDescriptorImpl valueDescriptor = ((ValueDescriptorImpl)descriptor);
+    final DebuggerContextImpl debuggerContext = tree.getDebuggerContext();
+    final DebugProcessImpl debugProcess = debuggerContext.getDebugProcess();
+    final ValueMarkup markup = valueDescriptor.getMarkup(debugProcess);
+    debugProcess.getManagerThread().invoke(new DebuggerContextCommandImpl(debuggerContext) {
+      public Priority getPriority() {
+        return Priority.HIGH;
+      }
+      public void threadAction() {
+        boolean sessionRefreshNeeded = true;
+        try {
+          if (markup != null) {
+            valueDescriptor.setMarkup(debugProcess, null);
+          }
+          else {
+            final String defaultText = valueDescriptor.getName();
+            final Ref<Pair<ValueMarkup,Boolean>> result = new Ref<Pair<ValueMarkup, Boolean>>(null);
+            try {
+              final boolean suggestAdditionalMarkup = canSuggestAdditionalMarkup(debugProcess, valueDescriptor.getValue());
+              SwingUtilities.invokeAndWait(new Runnable() {
+                public void run() {
+                  ObjectMarkupPropertiesDialog dialog = new ObjectMarkupPropertiesDialog(defaultText, suggestAdditionalMarkup);
+                  dialog.show();
+                  if (dialog.isOK()) {
+                    result.set(Pair.create(dialog.getConfiguredMarkup(), dialog.isMarkAdditionalFields()));
+                  }
+                }
+              });
+            }
+            catch (InterruptedException ignored) {
+            }
+            catch (InvocationTargetException e) {
+              LOG.error(e);
+            }
+            final Pair<ValueMarkup, Boolean> pair = result.get();
+            if (pair != null) {
+              valueDescriptor.setMarkup(debugProcess, pair.first);
+              if (pair.second) {
+                final Value value = valueDescriptor.getValue();
+                final Map<ObjectReference, ValueMarkup> additionalMarkup = suggestMarkup((ObjectReference)value);
+                if (!additionalMarkup.isEmpty()) {
+                  final Map<ObjectReference, ValueMarkup> map = NodeDescriptorImpl.getMarkupMap(debugProcess);
+                  if (map != null) {
+                    for (Map.Entry<ObjectReference, ValueMarkup> entry : additionalMarkup.entrySet()) {
+                      final ObjectReference key = entry.getKey();
+                      if (!map.containsKey(key)) {
+                        map.put(key, entry.getValue());
+                      }
+                    }
+                  }
+                }
+              }
+            }
+            else {
+              sessionRefreshNeeded = false;
+            }
+          }
+        }
+        finally {
+          final boolean _sessionRefreshNeeded = sessionRefreshNeeded;
+          SwingUtilities.invokeLater(new Runnable() {
+            public void run() {
+              tree.restoreState(node);
+              final TreeBuilder model = tree.getMutableModel();
+              refreshLabelsRecursively(model.getRoot(), model, valueDescriptor.getValue());
+              if (_sessionRefreshNeeded) {
+                final DebuggerSession session = debuggerContext.getDebuggerSession();
+                if (session != null) {
+                  session.refresh(true);
+                }
+              }
+            }
+
+            private void refreshLabelsRecursively(Object node, TreeBuilder model, Value value) {
+              if (node instanceof DebuggerTreeNodeImpl) {
+                final DebuggerTreeNodeImpl _node = (DebuggerTreeNodeImpl)node;
+                final NodeDescriptorImpl descriptor = _node.getDescriptor();
+                if (descriptor instanceof ValueDescriptor && Comparing.equal(value, ((ValueDescriptor)descriptor).getValue())) {
+                  _node.labelChanged();
+                }
+              }
+              final int childCount = model.getChildCount(node);
+              for (int idx = 0; idx < childCount; idx++) {
+                refreshLabelsRecursively(model.getChild(node, idx), model, value);
+              }
+            }
+
+          });
+        }
+      }
+    });
+  }
+
+  private static boolean canSuggestAdditionalMarkup(DebugProcessImpl debugProcess, Value value) {
+    if (!debugProcess.getVirtualMachineProxy().canGetInstanceInfo()) {
+      return false;
+    }
+    if (!(value instanceof ObjectReference)) {
+      return false;
+    }
+    final ObjectReference objRef = (ObjectReference)value;
+    if (objRef instanceof ArrayReference || objRef instanceof ClassObjectReference || objRef instanceof ThreadReference || objRef instanceof ThreadGroupReference || objRef instanceof ClassLoaderReference) {
+      return false;
+    }
+    return true;
+  }
+
+  private static Map<ObjectReference, ValueMarkup> suggestMarkup(ObjectReference objRef) {
+    final Map<ObjectReference, ValueMarkup> result = new HashMap<ObjectReference, ValueMarkup>();
+    for (ObjectReference ref : getReferringObjects(objRef)) {
+      if (!(ref instanceof ClassObjectReference)) {
+        // consider references from statisc fields only
+        continue;
+      }
+      final ReferenceType refType = ((ClassObjectReference)ref).reflectedType();
+      if (!refType.isAbstract()) {
+        continue;
+      }
+      for (Field field : refType.visibleFields()) {
+        if (!(field.isStatic() && field.isFinal())) {
+          continue;
+        }
+        if (DebuggerUtils.isPrimitiveType(field.typeName())) {
+          continue;
+        }
+        final Value fieldValue = refType.getValue(field);
+        if (!(fieldValue instanceof ObjectReference)) {
+          continue;
+        }
+        final ValueMarkup markup = result.get((ObjectReference)fieldValue);
+
+        final String fieldName = field.name();
+        final Color autoMarkupColor = getAutoMarkupColor();
+        if (markup == null) {
+          result.put((ObjectReference)fieldValue, new ValueMarkup(fieldName, autoMarkupColor, createMarkupTooltipText(null, refType, fieldName)));
+        }
+        else {
+          final String currentText = markup.getText();
+          if (!currentText.contains(fieldName)) {
+            final String currentTooltip = markup.getToolTipText();
+            final String tooltip = createMarkupTooltipText(currentTooltip, refType, fieldName);
+            result.put((ObjectReference)fieldValue, new ValueMarkup(currentText + ", " + fieldName, autoMarkupColor, tooltip));
+          }
+        }
+      }
+    }
+    return result;
+  }
+
+  private static List<ObjectReference> getReferringObjects(ObjectReference value) {
+    try {
+      return value.referringObjects(AUTO_MARKUP_REFERRING_OBJECTS_LIMIT);
+    }
+    catch (UnsupportedOperationException e) {
+      LOG.info(e);
+    }
+    return Collections.emptyList();
+  }
+
+  private static String createMarkupTooltipText(@Nullable String prefix, ReferenceType refType, String fieldName) {
+    final StringBuilder builder = new StringBuilder();
+    if (prefix == null) {
+      builder.append("Value referenced from:");
+    }
+    else {
+      builder.append(prefix);
+    }
+    return builder.append("<br><b>").append(refType.name()).append(".").append(fieldName).append("</b>").toString();
+  }
+
+  @Override
+  public boolean isEnabled(@NotNull Project project, AnActionEvent event) {
+    final DebuggerTreeNodeImpl node = DebuggerAction.getSelectedNode(event.getDataContext());
+    return node != null && node.getDescriptor() instanceof ValueDescriptor;
+  }
+
+  @Override
+  public boolean isHidden(@NotNull Project project, AnActionEvent event) {
+    return DebuggerAction.getSelectedNode(event.getDataContext()) == null;
+  }
+
+  @Override
+  public boolean isMarked(@NotNull Project project, @NotNull AnActionEvent event) {
+    final DebuggerTreeNodeImpl node = DebuggerAction.getSelectedNode(event.getDataContext());
+    if (node == null) return false;
+
+    final NodeDescriptorImpl descriptor = node.getDescriptor();
+    if (!(descriptor instanceof ValueDescriptor)) return false;
+
+    DebugProcess debugProcess = node.getTree().getDebuggerContext().getDebugProcess();
+    return ((ValueDescriptor)descriptor).getMarkup(debugProcess) != null;
+  }
+
+  public static Color getAutoMarkupColor() {
+    final EditorColorsManager manager = EditorColorsManager.getInstance();
+    final TextAttributes textAttributes = manager.getGlobalScheme().getAttributes(HighlightInfoType.STATIC_FIELD.getAttributesKey());
+    return textAttributes.getForegroundColor();
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/JavaSmartStepIntoHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/JavaSmartStepIntoHandler.java
new file mode 100644
index 0000000..c2d204f
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/JavaSmartStepIntoHandler.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2000-2011 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.debugger.actions;
+
+import com.intellij.debugger.SourcePosition;
+import com.intellij.lang.java.JavaLanguage;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.*;
+import com.intellij.util.containers.OrderedSet;
+import com.intellij.util.text.CharArrayUtil;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * User: Alexander Podkhalyuzin
+ * Date: 22.11.11
+ */
+public class JavaSmartStepIntoHandler extends JvmSmartStepIntoHandler {
+  @Override
+  public boolean isAvailable(final SourcePosition position) {
+    final PsiFile file = position.getFile();
+    return file.getLanguage().isKindOf(JavaLanguage.INSTANCE);
+  }
+
+  @Override
+  public List<PsiMethod> findReferencedMethods(final SourcePosition position) {
+    final int line = position.getLine();
+    if (line < 0) {
+      return Collections.emptyList(); // the document has been changed
+    }
+
+    final PsiFile file = position.getFile();
+    final VirtualFile vFile = file.getVirtualFile();
+    if (vFile == null) {
+      // the file is not physical
+      return Collections.emptyList();
+    }
+
+    final Document doc = FileDocumentManager.getInstance().getDocument(vFile);
+    if (doc == null) return Collections.emptyList();
+    if (line >= doc.getLineCount()) {
+      return Collections.emptyList(); // the document has been changed
+    }
+    final int startOffset = doc.getLineStartOffset(line);
+    final TextRange lineRange = new TextRange(startOffset, doc.getLineEndOffset(line));
+    final int offset = CharArrayUtil.shiftForward(doc.getCharsSequence(), startOffset, " \t");
+    PsiElement element = file.findElementAt(offset);
+    if (element != null && !(element instanceof PsiCompiledElement)) {
+      do {
+        final PsiElement parent = element.getParent();
+        if (parent == null || (parent.getTextOffset() < lineRange.getStartOffset())) {
+          break;
+        }
+        element = parent;
+      }
+      while(true);
+
+      //noinspection unchecked
+      final List<PsiMethod> methods = new OrderedSet<PsiMethod>();
+      final PsiElementVisitor methodCollector = new JavaRecursiveElementWalkingVisitor() {
+        @Override public void visitAnonymousClass(PsiAnonymousClass aClass) { /*skip annonymous classes*/ }
+
+        @Override public void visitStatement(PsiStatement statement) {
+          if (lineRange.intersects(statement.getTextRange())) {
+            super.visitStatement(statement);
+          }
+        }
+
+        @Override public void visitCallExpression(final PsiCallExpression expression) {
+          final PsiMethod psiMethod = expression.resolveMethod();
+          if (psiMethod != null) {
+            methods.add(psiMethod);
+          }
+          super.visitCallExpression(expression);
+        }
+      };
+      element.accept(methodCollector);
+      for (PsiElement sibling = element.getNextSibling(); sibling != null; sibling = sibling.getNextSibling()) {
+        if (!lineRange.intersects(sibling.getTextRange())) {
+          break;
+        }
+        sibling.accept(methodCollector);
+      }
+      return methods;
+    }
+    return Collections.emptyList();
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/JumpToObjectAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/JumpToObjectAction.java
new file mode 100644
index 0000000..89e32bc
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/JumpToObjectAction.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.debugger.SourcePosition;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.JVMNameUtil;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
+import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl;
+import com.intellij.debugger.ui.tree.ValueDescriptor;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.Computable;
+import com.intellij.psi.PsiClass;
+import com.sun.jdi.*;
+
+import java.util.List;
+
+public class JumpToObjectAction extends DebuggerAction{
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.actions.JumpToObjectAction");
+  public void actionPerformed(AnActionEvent e) {
+    DebuggerTreeNodeImpl selectedNode = getSelectedNode(e.getDataContext());
+    if(selectedNode == null) {
+      return;
+    }
+
+    final NodeDescriptorImpl descriptor = selectedNode.getDescriptor();
+    if(!(descriptor instanceof ValueDescriptor)) {
+      return;
+    }
+
+    DebuggerContextImpl debuggerContext = getDebuggerContext(e.getDataContext());
+    final DebugProcessImpl debugProcess = debuggerContext.getDebugProcess();
+    if(debugProcess == null) {
+      return;
+    }
+
+    debugProcess.getManagerThread().schedule(new NavigateCommand(debuggerContext, (ValueDescriptor)descriptor, debugProcess, e));
+  }
+
+  public void update(final AnActionEvent e) {
+    if(!isFirstStart(e)) {
+      return;
+    }
+
+    final DebuggerContextImpl debuggerContext = getDebuggerContext(e.getDataContext());
+    final DebugProcessImpl debugProcess = debuggerContext.getDebugProcess();
+    if(debugProcess == null) {
+      e.getPresentation().setVisible(false);
+      return;
+    }
+
+    DebuggerTreeNodeImpl selectedNode = getSelectedNode(e.getDataContext());
+    if(selectedNode == null) {
+      e.getPresentation().setVisible(false);
+      return;
+    }
+
+    final NodeDescriptorImpl descriptor = selectedNode.getDescriptor();
+    if (descriptor instanceof ValueDescriptor) {
+      debugProcess.getManagerThread().schedule(new EnableCommand(debuggerContext, (ValueDescriptor)descriptor, debugProcess, e));
+    }
+    else {
+      e.getPresentation().setVisible(false);
+    }
+  }
+
+  private SourcePosition calcPosition(final ValueDescriptor descriptor, final DebugProcessImpl debugProcess) throws ClassNotLoadedException {
+    final Value value = descriptor.getValue();
+    if(value == null) {
+      return null;
+    }
+
+    Type type = value.type();
+    if(type == null) {
+      return null;
+    }
+
+    try {
+      if(type instanceof ArrayType) {
+        type = ((ArrayType)type).componentType();
+      }
+      if(type instanceof ClassType) {
+        final ClassType clsType = (ClassType)type;
+        final List<Location> locations = clsType.allLineLocations();
+        if(locations.size() > 0) {
+          final Location location = locations.get(0);
+          return ApplicationManager.getApplication().runReadAction(new Computable<SourcePosition>() {
+            public SourcePosition compute() {
+              SourcePosition position = debugProcess.getPositionManager().getSourcePosition(location);
+              // adjust position for non-anonymous classes
+              if (clsType.name().indexOf("$") < 0) {
+                final PsiClass classAt = position != null? JVMNameUtil.getClassAt(position) : null;
+                if (classAt != null) {
+                  final SourcePosition classPosition = SourcePosition.createFromElement(classAt);
+                  if (classPosition != null) {
+                    position = classPosition;
+                  }
+                }
+              }
+              return position;
+            }
+          });
+        }
+      }
+    }
+    catch (ClassNotPreparedException e) {
+      LOG.debug(e);
+    }
+    catch (AbsentInformationException e) {
+      LOG.debug(e);
+    }
+    return null;
+  }
+
+  private class NavigateCommand extends SourcePositionCommand {
+    public NavigateCommand(final DebuggerContextImpl debuggerContext, final ValueDescriptor descriptor, final DebugProcessImpl debugProcess, final AnActionEvent e) {
+      super(debuggerContext, descriptor, debugProcess, e);
+    }
+    protected NavigateCommand createRetryCommand() {
+      return new NavigateCommand(myDebuggerContext, myDescriptor, myDebugProcess, myActionEvent);
+    }
+    protected void doAction(final SourcePosition sourcePosition) {
+      if (sourcePosition != null) {
+        sourcePosition.navigate(true);
+      }
+    }
+  }
+
+  private class EnableCommand extends SourcePositionCommand {
+    public EnableCommand(final DebuggerContextImpl debuggerContext, final ValueDescriptor descriptor, final DebugProcessImpl debugProcess, final AnActionEvent e) {
+      super(debuggerContext, descriptor, debugProcess, e);
+    }
+    protected EnableCommand createRetryCommand() {
+      return new EnableCommand(myDebuggerContext, myDescriptor, myDebugProcess, myActionEvent);
+    }
+    protected void doAction(final SourcePosition sourcePosition) {
+      enableAction(myActionEvent, sourcePosition != null);
+    }
+  }
+
+  public abstract class SourcePositionCommand extends SuspendContextCommandImpl {
+    protected final DebuggerContextImpl myDebuggerContext;
+    protected final ValueDescriptor myDescriptor;
+    protected final DebugProcessImpl myDebugProcess;
+    protected final AnActionEvent myActionEvent;
+
+    public SourcePositionCommand(final DebuggerContextImpl debuggerContext,
+                                 final ValueDescriptor descriptor,
+                                 final DebugProcessImpl debugProcess,
+                                 final AnActionEvent actionEvent) {
+      super(debuggerContext.getSuspendContext());
+      myDebuggerContext = debuggerContext;
+      myDescriptor = descriptor;
+      myDebugProcess = debugProcess;
+      myActionEvent = actionEvent;
+    }
+
+    public final void contextAction() throws Exception {
+      try {
+        doAction(calcPosition(myDescriptor, myDebugProcess));
+      }
+      catch (ClassNotLoadedException ex) {
+        final String className = ex.className();
+        if (loadClass(className) != null) {
+          myDebugProcess.getManagerThread().schedule(createRetryCommand());
+        }
+      }
+    }
+
+    protected abstract SourcePositionCommand createRetryCommand();
+
+    protected abstract void doAction(SourcePosition sourcePosition);
+
+    private ReferenceType loadClass(final String className) {
+      final EvaluationContextImpl eContext = myDebuggerContext.createEvaluationContext();
+      try {
+        return myDebugProcess.loadClass(eContext, className, eContext.getClassLoader());
+      }
+      catch(Throwable ignored) {
+      }
+      return null;
+    }
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/JvmSmartStepIntoActionHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/JvmSmartStepIntoActionHandler.java
new file mode 100644
index 0000000..512ab13
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/JvmSmartStepIntoActionHandler.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.SourcePosition;
+import com.intellij.debugger.engine.RequestHint;
+import com.intellij.debugger.engine.SuspendContextImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.extensions.Extensions;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.fileEditor.FileEditor;
+import com.intellij.openapi.fileEditor.FileEditorManager;
+import com.intellij.openapi.fileEditor.TextEditor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.popup.JBPopupFactory;
+import com.intellij.openapi.ui.popup.ListPopup;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.*;
+import com.intellij.ui.awt.RelativePoint;
+import com.intellij.util.containers.OrderedSet;
+import com.intellij.util.text.CharArrayUtil;
+import com.intellij.xdebugger.impl.actions.DebuggerActionHandler;
+import com.intellij.xdebugger.impl.ui.DebuggerUIUtil;
+import gnu.trove.TObjectHashingStrategy;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collections;
+import java.util.List;
+
+public class JvmSmartStepIntoActionHandler extends DebuggerActionHandler {
+  public void perform(@NotNull final Project project, final AnActionEvent event) {
+    final DebuggerContextImpl debuggerContext = (DebuggerManagerEx.getInstanceEx(project)).getContext();
+    doStep(project, debuggerContext.getSourcePosition(), debuggerContext.getDebuggerSession());
+  }
+
+  private static void doStep(final @NotNull Project project, final @Nullable SourcePosition position, final @NotNull DebuggerSession session) {
+    final VirtualFile file = position != null ? position.getFile().getVirtualFile() : null;
+    final FileEditor fileEditor = file != null? FileEditorManager.getInstance(project).getSelectedEditor(file) : null;
+    if (fileEditor instanceof TextEditor) {
+      for (JvmSmartStepIntoHandler handler : Extensions.getExtensions(JvmSmartStepIntoHandler.EP_NAME)) {
+        if (handler.isAvailable(position) && handler.doSmartStep(position, session, (TextEditor)fileEditor)) return;
+      }
+    }
+    session.stepInto(true, null);
+  }
+
+  public boolean isEnabled(@NotNull final Project project, final AnActionEvent event) {
+    final DebuggerContextImpl context = (DebuggerManagerEx.getInstanceEx(project)).getContext();
+    DebuggerSession debuggerSession = context.getDebuggerSession();
+    final boolean isPaused = debuggerSession != null && debuggerSession.isPaused();
+    final SuspendContextImpl suspendContext = context.getSuspendContext();
+    final boolean hasCurrentThread = suspendContext != null && suspendContext.getThread() != null;
+    return isPaused && hasCurrentThread;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/JvmSmartStepIntoHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/JvmSmartStepIntoHandler.java
new file mode 100644
index 0000000..d02029d
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/JvmSmartStepIntoHandler.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2000-2011 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.debugger.actions;
+
+import com.intellij.debugger.SourcePosition;
+import com.intellij.debugger.engine.RequestHint;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.openapi.fileEditor.TextEditor;
+import com.intellij.openapi.ui.popup.JBPopupFactory;
+import com.intellij.openapi.ui.popup.ListPopup;
+import com.intellij.psi.PsiMethod;
+import com.intellij.ui.awt.RelativePoint;
+import com.intellij.xdebugger.impl.ui.DebuggerUIUtil;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+
+/**
+ * User: Alexander Podkhalyuzin
+ * Date: 22.11.11
+ */
+public abstract class JvmSmartStepIntoHandler {
+  public static ExtensionPointName<JvmSmartStepIntoHandler> EP_NAME = ExtensionPointName.create("com.intellij.debugger.jvmSmartStepIntoHandler");
+
+  public abstract List<PsiMethod> findReferencedMethods(SourcePosition position);
+
+  public abstract boolean isAvailable(SourcePosition position);
+
+  /**
+   * Override this if you haven't PsiMethod, like in Kotlin.
+   * @param position
+   * @param session
+   * @param fileEditor
+   * @return false to continue for another handler or for default action (step into)
+   */
+  public boolean doSmartStep(SourcePosition position, final DebuggerSession session, TextEditor fileEditor) {
+    final List<PsiMethod> methods = findReferencedMethods(position);
+    if (methods.size() > 0) {
+      if (methods.size() == 1) {
+        session.stepInto(true, getSmartStepFilter(methods.get(0)));
+      }
+      else {
+        final PsiMethodListPopupStep popupStep = new PsiMethodListPopupStep(methods, new PsiMethodListPopupStep.OnChooseRunnable() {
+          public void execute(PsiMethod chosenMethod) {
+            session.stepInto(true, getSmartStepFilter(chosenMethod));
+          }
+        });
+        final ListPopup popup = JBPopupFactory.getInstance().createListPopup(popupStep);
+        final RelativePoint point = DebuggerUIUtil.calcPopupLocation(((TextEditor)fileEditor).getEditor(), position.getLine());
+        popup.show(point);
+      }
+      return true;
+    }
+    return false;
+  }
+
+  /**
+   * Override in case if your JVMNames slightly different then it can be provided by getJvmSignature method.
+   * @param method
+   * @return SmartStepFilter
+   */
+  protected RequestHint.SmartStepFilter getSmartStepFilter(PsiMethod method) {
+    return new RequestHint.SmartStepFilter(method);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/MuteBreakpointsActionHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/MuteBreakpointsActionHandler.java
new file mode 100644
index 0000000..f42c06b
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/MuteBreakpointsActionHandler.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.project.Project;
+import com.intellij.xdebugger.impl.actions.DebuggerToggleActionHandler;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: Mar 15, 2005
+ */
+public class MuteBreakpointsActionHandler extends DebuggerToggleActionHandler {
+  public boolean isSelected(@NotNull final Project project, final AnActionEvent event) {
+    DebuggerContextImpl context = DebuggerAction.getDebuggerContext(event.getDataContext());
+    DebugProcessImpl debugProcess = context.getDebugProcess();
+    return debugProcess != null && debugProcess.areBreakpointsMuted();
+  }
+
+  public void setSelected(@NotNull final Project project, final AnActionEvent event, final boolean state) {
+    DebuggerContextImpl context = DebuggerAction.getDebuggerContext(event.getDataContext());
+    final DebugProcessImpl debugProcess = context.getDebugProcess();
+    if(debugProcess != null) {
+      debugProcess.setBreakpointsMuted(state);
+    }
+  }
+
+  public boolean isEnabled(@NotNull final Project project, final AnActionEvent event) {
+    DebuggerContextImpl context = DebuggerAction.getDebuggerContext(event.getDataContext());
+    final DebugProcessImpl debugProcess = context.getDebugProcess();
+    return debugProcess != null; 
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/NewWatchAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/NewWatchAction.java
new file mode 100644
index 0000000..b7289f5
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/NewWatchAction.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class NewWatchAction
+ * @author Jeka
+ */
+package com.intellij.debugger.actions;
+
+import com.intellij.debugger.ui.DebuggerPanelsManager;
+import com.intellij.debugger.ui.impl.MainWatchPanel;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.PlatformDataKeys;
+import com.intellij.openapi.project.Project;
+
+public class NewWatchAction extends DebuggerAction {
+  public void actionPerformed(final AnActionEvent e) {
+    Project project = PlatformDataKeys.PROJECT.getData(e.getDataContext());
+    if(project == null) return;
+
+    final MainWatchPanel watchPanel = DebuggerPanelsManager.getInstance(project).getWatchPanel();
+    if (watchPanel != null) {
+      watchPanel.newWatch();
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/ObjectMarkupPropertiesDialog.form b/java/debugger/impl/src/com/intellij/debugger/actions/ObjectMarkupPropertiesDialog.form
new file mode 100644
index 0000000..a0b7a67
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/ObjectMarkupPropertiesDialog.form
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.debugger.actions.ObjectMarkupPropertiesDialog">
+  <grid id="27dc6" binding="myAdditionalPropertiesPanel" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+    <margin top="5" left="0" bottom="0" right="0"/>
+    <constraints>
+      <xy x="20" y="20" width="372" height="96"/>
+    </constraints>
+    <properties/>
+    <border type="none"/>
+    <children>
+      <component id="1dc00" class="com.intellij.openapi.ui.ex.MultiLineLabel" binding="myDescriptionLabel">
+        <constraints>
+          <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties>
+          <text value=""/>
+        </properties>
+      </component>
+      <component id="d6e49" class="javax.swing.JCheckBox" binding="myCbMarkAdditionalFields">
+        <constraints>
+          <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties>
+          <text value="&amp;Mark values referenced from constant fields"/>
+        </properties>
+      </component>
+    </children>
+  </grid>
+</form>
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/ObjectMarkupPropertiesDialog.java b/java/debugger/impl/src/com/intellij/debugger/actions/ObjectMarkupPropertiesDialog.java
new file mode 100644
index 0000000..cd4aa14
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/ObjectMarkupPropertiesDialog.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.ide.util.PropertiesComponent;
+import com.intellij.openapi.ui.ex.MultiLineLabel;
+import com.intellij.xdebugger.impl.ui.tree.ValueMarkerPresentationDialogBase;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import java.awt.*;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: Feb 4, 2007
+ */
+public class ObjectMarkupPropertiesDialog extends ValueMarkerPresentationDialogBase {
+  @NonNls private static final String MARK_ALL_REFERENCED_VALUES_KEY = "debugger.mark.all.referenced.values";
+  private JCheckBox myCbMarkAdditionalFields;
+  private final boolean mySuggestAdditionalMarkup;
+  private JPanel myAdditionalPropertiesPanel;
+  private MultiLineLabel myDescriptionLabel;
+
+  public ObjectMarkupPropertiesDialog(@NotNull final String defaultText, boolean suggestAdditionalMarkup) {
+    super(defaultText);
+    mySuggestAdditionalMarkup = suggestAdditionalMarkup;
+    myDescriptionLabel.setText("If the value is referenced by a constant field of an abstract class,\n" +
+                               "IDEA could additionally mark all values referenced from this class with the names of referencing fields.");
+    myCbMarkAdditionalFields.setSelected(PropertiesComponent.getInstance().getBoolean(MARK_ALL_REFERENCED_VALUES_KEY, true));
+    init();
+  }
+
+  @Override
+  protected void doOKAction() {
+    if (mySuggestAdditionalMarkup) {
+      PropertiesComponent.getInstance().setValue(MARK_ALL_REFERENCED_VALUES_KEY, Boolean.toString(myCbMarkAdditionalFields.isSelected()));
+    }
+    super.doOKAction();
+  }
+
+  @Override
+  protected JComponent createCenterPanel() {
+    JComponent mainPanel = super.createCenterPanel();
+    if (!mySuggestAdditionalMarkup) {
+      return mainPanel;
+    }
+    JPanel panel = new JPanel(new BorderLayout());
+    panel.add(BorderLayout.CENTER, mainPanel);
+    panel.add(BorderLayout.SOUTH, myAdditionalPropertiesPanel);
+    return panel;
+  }
+
+  public boolean isMarkAdditionalFields() {
+    return mySuggestAdditionalMarkup && myCbMarkAdditionalFields.isSelected();
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/PauseActionHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/PauseActionHandler.java
new file mode 100644
index 0000000..7f55f62
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/PauseActionHandler.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.engine.SuspendContextImpl;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.project.Project;
+import com.intellij.xdebugger.impl.actions.DebuggerActionHandler;
+import com.sun.jdi.request.EventRequest;
+import org.jetbrains.annotations.NotNull;
+
+public class PauseActionHandler extends DebuggerActionHandler {
+  public void perform(@NotNull final Project project, final AnActionEvent event) {
+    (DebuggerManagerEx.getInstanceEx(project)).getContext().getDebuggerSession().pause();
+  }
+
+  @Override
+  public boolean isHidden(@NotNull Project project, AnActionEvent event) {
+    return DebuggerManagerEx.getInstanceEx(project).getContext().getDebuggerSession() == null;
+  }
+
+  public boolean isEnabled(@NotNull final Project project, final AnActionEvent event) {
+    final DebuggerSession debuggerSession = DebuggerManagerEx.getInstanceEx(project).getContext().getDebuggerSession();
+    return debuggerSession != null && !debuggerSession.getProcess().isPausePressed() &&
+           (debuggerSession.isEvaluating() || 
+            debuggerSession.isRunning() || isSingleThreadSuspended(debuggerSession)
+           );
+  }
+
+  private static boolean isSingleThreadSuspended(final DebuggerSession debuggerSession) {
+    final SuspendContextImpl suspendContext = debuggerSession.getContextManager().getContext().getSuspendContext();
+    return suspendContext != null && !suspendContext.isResumed() && suspendContext.getSuspendPolicy() == EventRequest.SUSPEND_EVENT_THREAD;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/PlaceInDocument.java b/java/debugger/impl/src/com/intellij/debugger/actions/PlaceInDocument.java
new file mode 100644
index 0000000..808f226
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/PlaceInDocument.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.openapi.editor.Document;
+
+/**
+ * User: lex
+ * Date: Oct 7, 2003
+ * Time: 3:12:54 PM
+ */
+interface PlaceInDocument {
+  public Document getDocument();
+  public int      getOffset();
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/PopFrameAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/PopFrameAction.java
new file mode 100644
index 0000000..f2f310c
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/PopFrameAction.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * @author Eugene Zhuravlev
+ */
+package com.intellij.debugger.actions;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.SuspendContextImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.jdi.StackFrameProxyImpl;
+import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
+import com.intellij.debugger.ui.impl.watch.*;
+import com.intellij.idea.ActionsBundle;
+import com.intellij.openapi.actionSystem.ActionPlaces;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.PlatformDataKeys;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.Messages;
+import com.sun.jdi.InvalidStackFrameException;
+import com.sun.jdi.NativeMethodException;
+import com.sun.jdi.VMDisconnectedException;
+import org.jetbrains.annotations.Nullable;
+
+public class PopFrameAction extends DebuggerAction {
+  public void actionPerformed(AnActionEvent e) {
+    Project project = e.getData(PlatformDataKeys.PROJECT);
+    StackFrameProxyImpl stackFrame = getStackFrameProxy(e);
+    if(stackFrame == null) {
+      return;
+    }
+    try {
+      DebuggerContextImpl debuggerContext = DebuggerAction.getDebuggerContext(e.getDataContext());
+      DebugProcessImpl debugProcess = debuggerContext.getDebugProcess();
+      if(debugProcess == null) {
+        return;
+      }
+      debugProcess.getManagerThread().schedule(debugProcess.createPopFrameCommand(debuggerContext, stackFrame));
+    }
+    catch (NativeMethodException e2){
+      Messages.showMessageDialog(project, DebuggerBundle.message("error.native.method.exception"), ActionsBundle.actionText(DebuggerActions.POP_FRAME), Messages.getErrorIcon());
+    }
+    catch (InvalidStackFrameException ignored) {
+    }
+    catch(VMDisconnectedException vde) {
+    }
+  }
+
+  @Nullable
+  private static StackFrameProxyImpl getStackFrameProxy(AnActionEvent e) {
+    DebuggerTreeNodeImpl selectedNode = getSelectedNode(e.getDataContext());
+    if(selectedNode != null) {
+      NodeDescriptorImpl descriptor = selectedNode.getDescriptor();
+      if(descriptor instanceof StackFrameDescriptorImpl) {
+        if(selectedNode.getNextSibling() != null) {
+          StackFrameDescriptorImpl frameDescriptor = ((StackFrameDescriptorImpl)descriptor);
+          return frameDescriptor.getFrameProxy();
+        }
+        return null;
+      }
+      else if(descriptor instanceof ThreadDescriptorImpl || descriptor instanceof ThreadGroupDescriptorImpl) {
+        return null;
+      }
+    }
+    DebuggerContextImpl debuggerContext = DebuggerAction.getDebuggerContext(e.getDataContext());
+    StackFrameProxyImpl frameProxy = debuggerContext.getFrameProxy();
+
+    if(frameProxy == null || frameProxy.isBottom()) {
+      return null;
+    }
+    return frameProxy;
+  }
+
+  private static boolean isAtBreakpoint(AnActionEvent e) {
+    DebuggerTreeNodeImpl selectedNode = getSelectedNode(e.getDataContext());
+    if(selectedNode != null && selectedNode.getDescriptor() instanceof StackFrameDescriptorImpl) {
+      DebuggerTreeNodeImpl parent = selectedNode.getParent();
+      if(parent != null) {
+        return ((ThreadDescriptorImpl)parent.getDescriptor()).isAtBreakpoint();
+      }
+    }
+    DebuggerContextImpl debuggerContext = DebuggerAction.getDebuggerContext(e.getDataContext());
+    SuspendContextImpl suspendContext = debuggerContext.getSuspendContext();
+    return suspendContext != null && debuggerContext.getThreadProxy() == suspendContext.getThread();
+  }
+
+  public void update(AnActionEvent e) {
+    boolean enable = false;
+    StackFrameProxyImpl stackFrameProxy = getStackFrameProxy(e);
+
+    if(stackFrameProxy != null && isAtBreakpoint(e)) {
+      VirtualMachineProxyImpl virtualMachineProxy = stackFrameProxy.getVirtualMachine();
+      enable = virtualMachineProxy.canPopFrames();
+    }
+
+    if(ActionPlaces.MAIN_MENU.equals(e.getPlace()) || ActionPlaces.DEBUGGER_TOOLBAR.equals(e.getPlace())) {
+      e.getPresentation().setEnabled(enable);
+    }
+    else {
+      e.getPresentation().setVisible(enable);
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/PsiMethodListPopupStep.java b/java/debugger/impl/src/com/intellij/debugger/actions/PsiMethodListPopupStep.java
new file mode 100644
index 0000000..7a6fde9
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/PsiMethodListPopupStep.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.openapi.ui.popup.*;
+import com.intellij.psi.PsiMethod;
+import com.intellij.psi.PsiSubstitutor;
+import com.intellij.psi.util.PsiFormatUtil;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import java.util.List;
+
+/**
+ * @author Eugene Zhuravlev
+*         Date: Nov 21, 2006
+*/
+class PsiMethodListPopupStep implements ListPopupStep {
+  private final List<PsiMethod> myMethods;
+  private final OnChooseRunnable myStepRunnable;
+
+
+  public static interface OnChooseRunnable {
+    void execute(PsiMethod chosenMethod);
+  }
+
+  public PsiMethodListPopupStep(final List<PsiMethod> methods, final OnChooseRunnable stepRunnable) {
+    myMethods = methods;
+    myStepRunnable = stepRunnable;
+  }
+
+  @NotNull
+  public List getValues() {
+    return myMethods;
+  }
+
+  public boolean isSelectable(Object value) {
+    return true;
+  }
+
+  public Icon getIconFor(Object aValue) {
+    if (aValue instanceof PsiMethod) {
+      PsiMethod method = (PsiMethod)aValue;
+      return method.getIcon(0);
+    }
+    return null;
+  }
+
+  @NotNull
+    public String getTextFor(Object value) {
+    if (value instanceof PsiMethod) {
+      return PsiFormatUtil.formatMethod(
+        (PsiMethod)value,
+        PsiSubstitutor.EMPTY,
+        PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_PARAMETERS,
+        PsiFormatUtil.SHOW_TYPE,
+        999
+      );
+    }
+    return value.toString();
+  }
+
+  public ListSeparator getSeparatorAbove(Object value) {
+    return null;
+  }
+
+  public int getDefaultOptionIndex() {
+    return 0;
+  }
+
+  public String getTitle() {
+    return DebuggerBundle.message("title.smart.step.popup");
+  }
+
+  public PopupStep onChosen(Object selectedValue, final boolean finalChoice) {
+    if (finalChoice) {
+      myStepRunnable.execute((PsiMethod)selectedValue);
+    }
+    return FINAL_CHOICE;
+  }
+
+  public Runnable getFinalRunnable() {
+    return null;
+  }
+
+  public boolean hasSubstep(Object selectedValue) {
+    return false;
+  }
+
+  public void canceled() {
+  }
+
+  public boolean isMnemonicsNavigationEnabled() {
+    return false;
+  }
+
+  public MnemonicNavigationFilter getMnemonicNavigationFilter() {
+    return null;
+  }
+
+  public boolean isSpeedSearchEnabled() {
+    return false;
+  }
+
+  public SpeedSearchFilter getSpeedSearchFilter() {
+    return null;
+  }
+
+  public boolean isAutoSelectionEnabled() {
+    return false;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/QuickEvaluateActionHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/QuickEvaluateActionHandler.java
new file mode 100644
index 0000000..d67b2bf
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/QuickEvaluateActionHandler.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class EvaluateAction
+ * @author Jeka
+ */
+package com.intellij.debugger.actions;
+
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.settings.DebuggerSettings;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.debugger.ui.ValueHint;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import com.intellij.xdebugger.impl.evaluate.quick.common.QuickEvaluateHandler;
+import com.intellij.xdebugger.impl.evaluate.quick.common.AbstractValueHint;
+import com.intellij.xdebugger.impl.evaluate.quick.common.ValueHintType;
+import org.jetbrains.annotations.NotNull;
+
+import java.awt.*;
+
+public class QuickEvaluateActionHandler extends QuickEvaluateHandler {
+
+  public boolean isEnabled(@NotNull final Project project) {
+    DebuggerSession debuggerSession = DebuggerManagerEx.getInstanceEx(project).getContext().getDebuggerSession();
+    return debuggerSession != null && debuggerSession.isPaused();
+  }
+
+  public AbstractValueHint createValueHint(@NotNull final Project project, @NotNull final Editor editor, @NotNull final Point point, final ValueHintType type) {
+    return ValueHint.createValueHint(project, editor, point, type);
+  }
+
+  public boolean canShowHint(@NotNull final Project project) {
+    DebuggerSession debuggerSession = DebuggerManagerEx.getInstanceEx(project).getContext().getDebuggerSession();
+    return debuggerSession != null && debuggerSession.isAttached();
+  }
+
+  public int getValueLookupDelay(final Project project) {
+    return DebuggerSettings.getInstance().VALUE_LOOKUP_DELAY;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/RemoveAllWatchesAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/RemoveAllWatchesAction.java
new file mode 100644
index 0000000..e677322
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/RemoveAllWatchesAction.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.debugger.ui.impl.watch.DebuggerTree;
+import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.Presentation;
+
+import java.util.Enumeration;
+
+/**
+ * User: lex
+ * Date: Sep 26, 2003
+ * Time: 6:24:44 PM
+ */
+public class RemoveAllWatchesAction extends RemoveWatchAction {
+  protected DebuggerTreeNodeImpl[] getNodesToDelete(AnActionEvent e) {
+    DebuggerTree tree = getTree(e.getDataContext());
+    if(tree == null) return null;
+    DebuggerTreeNodeImpl root = (DebuggerTreeNodeImpl)tree.getModel().getRoot();
+    DebuggerTreeNodeImpl [] result = new DebuggerTreeNodeImpl[root.getChildCount()];
+    int i = 0;
+    for(Enumeration enumeration = root.children(); enumeration.hasMoreElements(); i++) {
+      DebuggerTreeNodeImpl node = (DebuggerTreeNodeImpl)enumeration.nextElement();
+      result[i] = node;
+    }
+    return result;
+  }
+
+  protected void updatePresentation(Presentation presentation, int watchesCount) {
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/RemoveWatchAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/RemoveWatchAction.java
new file mode 100644
index 0000000..3222419
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/RemoveWatchAction.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.debugger.ui.impl.MainWatchPanel;
+import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
+import com.intellij.debugger.ui.impl.watch.WatchItemDescriptor;
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.Presentation;
+
+import java.util.ArrayList;
+
+public class RemoveWatchAction extends DebuggerAction {
+  protected DebuggerTreeNodeImpl[] getNodesToDelete(AnActionEvent e) {
+    DebuggerTreeNodeImpl[] selectedNodes = getSelectedNodes(e.getDataContext());
+    if(selectedNodes == null) return null;
+    ArrayList<DebuggerTreeNodeImpl> selectedWatches = new ArrayList<DebuggerTreeNodeImpl>();
+    for (int i = 0; i < selectedNodes.length; i++) {
+      if(selectedNodes[i].getDescriptor() instanceof WatchItemDescriptor) {
+        selectedWatches.add(selectedNodes[i]);
+      }
+    }
+
+    return selectedWatches.toArray(new DebuggerTreeNodeImpl[selectedWatches.size()]);
+  }
+
+  public void actionPerformed(AnActionEvent e) {
+    DebuggerTreeNodeImpl [] nodes = getNodesToDelete(e);
+    if (nodes == null || nodes.length == 0) return;
+
+    MainWatchPanel watchPanel = (MainWatchPanel)getPanel(e.getDataContext());
+
+    for (int i = 0; i < nodes.length; i++) {
+      DebuggerTreeNodeImpl node = nodes[i];
+      watchPanel.getWatchTree().removeWatch(node);
+    }
+  }
+
+  protected void updatePresentation(Presentation presentation, int watchesCount) {
+    presentation.setText(DebuggerBundle.message("action.remove.watch.text", watchesCount));
+  }
+
+  public void update(AnActionEvent event) {
+    Presentation presentation = event.getPresentation();
+    DebuggerTreeNodeImpl[] nodes = getNodesToDelete(event);
+    if (nodes != null && nodes.length > 0) {
+      presentation.setEnabled(true);
+    }
+    else {
+      presentation.setEnabled(false);
+    }
+    updatePresentation(presentation, nodes != null? nodes.length : 0);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/ResumeActionHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/ResumeActionHandler.java
new file mode 100644
index 0000000..0a975bf
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/ResumeActionHandler.java
@@ -0,0 +1,35 @@
+
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.project.Project;
+import com.intellij.xdebugger.impl.actions.DebuggerActionHandler;
+import org.jetbrains.annotations.NotNull;
+
+public class ResumeActionHandler extends DebuggerActionHandler {
+  public void perform(@NotNull final Project project, final AnActionEvent event) {
+    (DebuggerManagerEx.getInstanceEx(project)).getContext().getDebuggerSession().resume();
+  }
+
+  public boolean isEnabled(@NotNull final Project project, final AnActionEvent event) {
+    DebuggerSession debuggerSession = (DebuggerManagerEx.getInstanceEx(project)).getContext().getDebuggerSession();
+    return debuggerSession != null && debuggerSession.isPaused();
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/ResumeThreadAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/ResumeThreadAction.java
new file mode 100644
index 0000000..fe3ef56
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/ResumeThreadAction.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
+import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
+import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl;
+import com.intellij.debugger.ui.impl.watch.ThreadDescriptorImpl;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.Presentation;
+import com.sun.jdi.request.EventRequest;
+
+/**
+ * User: lex
+ * Date: Sep 26, 2003
+ * Time: 7:35:09 PM
+ */
+public class ResumeThreadAction extends DebuggerAction{
+  public void actionPerformed(final AnActionEvent e) {
+    DebuggerTreeNodeImpl[] selectedNode = getSelectedNodes(e.getDataContext());
+    final DebuggerContextImpl debuggerContext = getDebuggerContext(e.getDataContext());
+    final DebugProcessImpl debugProcess = debuggerContext.getDebugProcess();
+
+    //noinspection ConstantConditions
+    for (final DebuggerTreeNodeImpl debuggerTreeNode : selectedNode) {
+      final ThreadDescriptorImpl threadDescriptor = ((ThreadDescriptorImpl)debuggerTreeNode.getDescriptor());
+
+      if (threadDescriptor.isSuspended()) {
+        final ThreadReferenceProxyImpl thread = threadDescriptor.getThreadReference();
+        debugProcess.getManagerThread().schedule(new SuspendContextCommandImpl(debuggerContext.getSuspendContext()) {
+          public void contextAction() throws Exception {
+            debugProcess.createResumeThreadCommand(getSuspendContext(), thread).run();
+            debuggerTreeNode.calcValue();
+          }
+        });
+      }
+    }
+  }
+
+  public void update(AnActionEvent e) {
+    DebuggerTreeNodeImpl[] selectedNodes = getSelectedNodes(e.getDataContext());
+
+    boolean visible = false;
+    boolean enabled = false;
+    String text = DebuggerBundle.message("action.resume.thread.text.resume");
+
+    if(selectedNodes != null && selectedNodes.length > 0){
+      visible = true;
+      enabled = true;
+      for (DebuggerTreeNodeImpl selectedNode : selectedNodes) {
+        final NodeDescriptorImpl threadDescriptor = selectedNode.getDescriptor();
+        if (!(threadDescriptor instanceof ThreadDescriptorImpl) || !((ThreadDescriptorImpl)threadDescriptor).isSuspended()) {
+          visible = false;
+          break;
+        }
+      }
+      if (visible) {
+        for (DebuggerTreeNodeImpl selectedNode : selectedNodes) {
+          final ThreadDescriptorImpl threadDescriptor = (ThreadDescriptorImpl)selectedNode.getDescriptor();
+          if (threadDescriptor.getSuspendContext().getSuspendPolicy() == EventRequest.SUSPEND_ALL && !threadDescriptor.isFrozen()) {
+            enabled = false;
+            break;
+          }
+          else {
+            if (threadDescriptor.isFrozen()) {
+              text = DebuggerBundle.message("action.resume.thread.text.unfreeze");
+            }
+          }
+        }
+      }
+    }
+    final Presentation presentation = e.getPresentation();
+    presentation.setText(text);
+    presentation.setVisible(visible);
+    presentation.setEnabled(enabled);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/RunToCursorActionHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/RunToCursorActionHandler.java
new file mode 100644
index 0000000..56ed1c5
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/RunToCursorActionHandler.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/**
+ * class RunToCursorAction
+ * @author Jeka
+ */
+package com.intellij.debugger.actions;
+
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.DebuggerUtils;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.PlatformDataKeys;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.fileTypes.FileTypeManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiFile;
+import com.intellij.xdebugger.impl.actions.DebuggerActionHandler;
+import org.jetbrains.annotations.NotNull;
+
+public class RunToCursorActionHandler extends DebuggerActionHandler {
+  private final boolean myIgnoreBreakpoints;
+
+  public RunToCursorActionHandler() {
+    this(false);
+  }
+
+  protected RunToCursorActionHandler(boolean ignoreBreakpoints) {
+    myIgnoreBreakpoints = ignoreBreakpoints;
+  }
+
+  public boolean isEnabled(final @NotNull Project project, final AnActionEvent event) {
+
+    Editor editor = event.getData(PlatformDataKeys.EDITOR);
+
+    if (editor == null) {
+      return false;
+    }
+
+    PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
+    FileTypeManager fileTypeManager = FileTypeManager.getInstance();
+    if (file == null) {
+      return false;
+    }
+
+    final VirtualFile virtualFile = file.getVirtualFile();
+    FileType fileType = virtualFile != null ? virtualFile.getFileType() : null;
+    if (DebuggerUtils.supportsJVMDebugging(fileType) || DebuggerUtils.supportsJVMDebugging(file)) {
+      DebuggerSession debuggerSession = DebuggerManagerEx.getInstanceEx(project).getContext().getDebuggerSession();
+      return debuggerSession != null && debuggerSession.isPaused();
+    }
+
+    return false;
+  }
+
+
+  public void perform(@NotNull final Project project, final AnActionEvent event) {
+    Editor editor = event.getData(PlatformDataKeys.EDITOR);
+    if (editor == null) {
+      return;
+    }
+    DebuggerContextImpl context = DebuggerManagerEx.getInstanceEx(project).getContext();
+    DebugProcessImpl debugProcess = context.getDebugProcess();
+    if (debugProcess == null) {
+      return;
+    }
+    context.getDebuggerSession().runToCursor(editor.getDocument(), editor.getCaretModel().getLogicalPosition().line, myIgnoreBreakpoints);
+  }
+}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/SetValueAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/SetValueAction.java
new file mode 100644
index 0000000..9fd1825
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/SetValueAction.java
@@ -0,0 +1,524 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerInvocationUtil;
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.engine.ContextUtil;
+import com.intellij.debugger.engine.evaluation.*;
+import com.intellij.debugger.engine.evaluation.expression.*;
+import com.intellij.debugger.engine.events.DebuggerContextCommandImpl;
+import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
+import com.intellij.debugger.impl.*;
+import com.intellij.debugger.jdi.LocalVariableProxyImpl;
+import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
+import com.intellij.debugger.ui.DebuggerExpressionComboBox;
+import com.intellij.debugger.ui.EditorEvaluationCommand;
+import com.intellij.debugger.ui.impl.DebuggerTreeRenderer;
+import com.intellij.debugger.ui.impl.watch.*;
+import com.intellij.debugger.ui.tree.render.HexRenderer;
+import com.intellij.debugger.ui.tree.render.NodeRenderer;
+import com.intellij.debugger.ui.tree.render.ValueLabelRenderer;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.progress.ProcessCanceledException;
+import com.intellij.openapi.progress.util.ProgressIndicatorListenerAdapter;
+import com.intellij.openapi.progress.util.ProgressWindowWithNotification;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.Messages;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiFile;
+import com.intellij.ui.SimpleColoredComponent;
+import com.intellij.util.IJSwingUtilities;
+import com.sun.jdi.*;
+
+import javax.swing.*;
+
+/*
+ * Class SetValueAction
+ * @author Jeka
+ */
+public class SetValueAction extends DebuggerAction {
+  public void update(AnActionEvent e) {
+    boolean enable = false;
+    DebuggerTreeNodeImpl node = getSelectedNode(e.getDataContext());
+    if (node != null) {
+      NodeDescriptorImpl descriptor = node.getDescriptor();
+      if(descriptor instanceof ValueDescriptorImpl){
+        ValueDescriptorImpl valueDescriptor = ((ValueDescriptorImpl)descriptor);
+        enable = valueDescriptor.canSetValue();
+      }
+    }
+    e.getPresentation().setVisible(enable);
+  }
+
+  private void update(final DebuggerContextImpl context) {
+    DebuggerInvocationUtil.swingInvokeLater(context.getProject(), new Runnable() {
+      public void run() {
+        context.getDebuggerSession().refresh(false);
+      }
+    });
+    //node.setState(context);
+  }
+
+  public void actionPerformed(final AnActionEvent event) {
+    final DebuggerTreeNodeImpl node = getSelectedNode(event.getDataContext());
+    if (node == null) {
+      return;
+    }
+    final NodeDescriptorImpl descriptor = node.getDescriptor();
+    if (!(descriptor instanceof ValueDescriptorImpl)) {
+      return;
+    }
+    if(!((ValueDescriptorImpl)descriptor).canSetValue()) {
+      return;
+    }
+
+    final DebuggerTree tree = getTree(event.getDataContext());
+    final DebuggerContextImpl debuggerContext = getDebuggerContext(event.getDataContext());
+    tree.saveState(node);
+
+    if (descriptor instanceof FieldDescriptorImpl) {
+      FieldDescriptorImpl fieldDescriptor = (FieldDescriptorImpl)descriptor;
+      final Field field = fieldDescriptor.getField();
+      if (!field.isStatic()) {
+        final ObjectReference object = fieldDescriptor.getObject();
+        if (object != null) {
+          askAndSet(node, debuggerContext, new SetValueRunnable() {
+            public void setValue(EvaluationContextImpl evaluationContext, Value newValue) throws ClassNotLoadedException, InvalidTypeException, EvaluateException {
+              object.setValue(field, preprocessValue(evaluationContext, newValue, field.type()));
+              update(debuggerContext);
+            }
+
+            public ReferenceType loadClass(EvaluationContextImpl evaluationContext, String className) throws InvocationException,
+                                                                                                         ClassNotLoadedException,
+                                                                                                         IncompatibleThreadStateException,
+                                                                                                         InvalidTypeException,
+                                                                                                         EvaluateException {
+              return evaluationContext.getDebugProcess().loadClass(evaluationContext, className, field.declaringType().classLoader());
+            }
+          });
+        }
+      }
+      else {
+        // field is static
+        ReferenceType refType = field.declaringType();
+        if (refType instanceof ClassType) {
+          final ClassType classType = (ClassType)refType;
+          askAndSet(node, debuggerContext, new SetValueRunnable() {
+            public void setValue(EvaluationContextImpl evaluationContext, Value newValue) throws ClassNotLoadedException, InvalidTypeException, EvaluateException {
+              classType.setValue(field, preprocessValue(evaluationContext, newValue, field.type()));
+              update(debuggerContext);
+            }
+
+            public ReferenceType loadClass(EvaluationContextImpl evaluationContext, String className) throws InvocationException,
+                                                                                                         ClassNotLoadedException,
+                                                                                                         IncompatibleThreadStateException,
+                                                                                                         InvalidTypeException,
+                                                                                                         EvaluateException {
+              return evaluationContext.getDebugProcess().loadClass(evaluationContext, className,
+                                                                   field.declaringType().classLoader());
+            }
+          });
+        }
+      }
+    }
+    else if (descriptor instanceof LocalVariableDescriptorImpl) {
+      LocalVariableDescriptorImpl localDescriptor = (LocalVariableDescriptorImpl)descriptor;
+      final LocalVariableProxyImpl local = localDescriptor.getLocalVariable();
+      if (local != null) {
+        askAndSet(node, debuggerContext, new SetValueRunnable() {
+          public void setValue(EvaluationContextImpl evaluationContext, Value newValue) throws ClassNotLoadedException,
+                                                                                           InvalidTypeException,
+                                                                                           EvaluateException {
+            debuggerContext.getFrameProxy().setValue(local, preprocessValue(evaluationContext, newValue, local.getType()));
+            update(debuggerContext);
+          }
+
+          public ReferenceType loadClass(EvaluationContextImpl evaluationContext, String className) throws InvocationException,
+                                                                                                       ClassNotLoadedException,
+                                                                                                       IncompatibleThreadStateException,
+                                                                                                       InvalidTypeException,
+                                                                                                       EvaluateException {
+            return evaluationContext.getDebugProcess().loadClass(evaluationContext, className,
+                                                                 evaluationContext.getClassLoader());
+          }
+        });
+      }
+    }
+    else if (descriptor instanceof ArrayElementDescriptorImpl) {
+      final ArrayElementDescriptorImpl elementDescriptor = (ArrayElementDescriptorImpl)descriptor;
+      final ArrayReference array = elementDescriptor.getArray();
+      if (array != null) {
+        if (VirtualMachineProxyImpl.isCollected(array)) {
+          // will only be the case if debugger does not use ObjectReference.disableCollection() because of Patches.IBM_JDK_DISABLE_COLLECTION_BUG
+          Messages.showWarningDialog(tree, DebuggerBundle.message("evaluation.error.array.collected") + "\n"+ DebuggerBundle.message("warning.recalculate"), DebuggerBundle.message("title.set.value"));
+          node.getParent().calcValue();
+          return;
+        }
+        final ArrayType arrType = (ArrayType)array.referenceType();
+        askAndSet(node, debuggerContext, new SetValueRunnable() {
+          public void setValue(EvaluationContextImpl evaluationContext, Value newValue) throws ClassNotLoadedException, InvalidTypeException, EvaluateException {
+            array.setValue(elementDescriptor.getIndex(), preprocessValue(evaluationContext, newValue, arrType.componentType()));
+            update(debuggerContext);
+          }
+
+          public ReferenceType loadClass(EvaluationContextImpl evaluationContext, String className) throws InvocationException,
+                                                                                                       ClassNotLoadedException,
+                                                                                                       IncompatibleThreadStateException,
+                                                                                                       InvalidTypeException,
+                                                                                                       EvaluateException {
+            return evaluationContext.getDebugProcess().loadClass(evaluationContext, className, arrType.classLoader());
+          }
+        });
+      }
+    }
+    else if (descriptor instanceof EvaluationDescriptor) {
+      final EvaluationDescriptor evaluationDescriptor = (EvaluationDescriptor)descriptor;
+      if (evaluationDescriptor.canSetValue()) {
+        askAndSet(node, debuggerContext, new SetValueRunnable() {
+          public void setValue(EvaluationContextImpl evaluationContext, Value newValue) throws ClassNotLoadedException, InvalidTypeException, EvaluateException {
+            final Modifier modifier = evaluationDescriptor.getModifier();
+            modifier.setValue(preprocessValue(evaluationContext, newValue, modifier.getExpectedType()));
+            update(debuggerContext);
+          }
+
+          public ReferenceType loadClass(EvaluationContextImpl evaluationContext, String className) throws InvocationException,
+                                                                                                       ClassNotLoadedException,
+                                                                                                       IncompatibleThreadStateException,
+                                                                                                       InvalidTypeException,
+                                                                                                       EvaluateException {
+            return evaluationContext.getDebugProcess().loadClass(evaluationContext, className,
+                                                                 evaluationContext.getClassLoader());
+          }
+        });
+      }
+    }
+  }
+
+  private Value preprocessValue(EvaluationContextImpl context, Value value, Type varType) throws EvaluateException {
+    if (value != null && "java.lang.String".equals(varType.name()) && !(value instanceof StringReference)) {
+      String v = DebuggerUtilsEx.getValueAsString(context, value);
+      if (v != null) {
+        value = context.getSuspendContext().getDebugProcess().getVirtualMachineProxy().mirrorOf(v);
+      }
+    }
+    if(value instanceof DoubleValue) {
+      double dValue = ((DoubleValue) value).doubleValue();
+      if(varType instanceof FloatType && Float.MIN_VALUE <= dValue && dValue <= Float.MAX_VALUE){
+        value = context.getSuspendContext().getDebugProcess().getVirtualMachineProxy().mirrorOf((float)dValue);
+      }
+    }
+    if (value != null) {
+      if (varType instanceof PrimitiveType) {
+        if (!(value instanceof PrimitiveValue)) {
+          value = (Value)new UnBoxingEvaluator(new IdentityEvaluator(value)).evaluate(context);
+        }
+      }
+      else if (UnBoxingEvaluator.isTypeUnboxable(varType.name())) {
+        // variable is not primitive and boxing/unboxing is applicable
+        if (value instanceof PrimitiveValue) {
+          value = (Value)new BoxingEvaluator(new IdentityEvaluator(value)).evaluate(context);
+        }
+      }
+    }
+    return value;
+  }
+
+  private static interface SetValueRunnable {
+    void setValue(EvaluationContextImpl evaluationContext, Value newValue) throws ClassNotLoadedException,
+                                                                                          InvalidTypeException,
+                                                                                          EvaluateException,
+                                                                                          IncompatibleThreadStateException;
+    ReferenceType loadClass(EvaluationContextImpl evaluationContext, String className) throws EvaluateException,
+                                                                                            InvocationException,
+                                                                                            ClassNotLoadedException,
+                                                                                            IncompatibleThreadStateException,
+                                                                                            InvalidTypeException;
+  }
+
+  private static void setValue(String expressionToShow, ExpressionEvaluator evaluator, EvaluationContextImpl evaluationContext, SetValueRunnable setValueRunnable) throws EvaluateException {
+    Value value;
+    try {
+      value = evaluator.evaluate(evaluationContext);
+
+      setValueRunnable.setValue(evaluationContext, value);
+    }
+    catch (IllegalArgumentException ex) {
+      throw EvaluateExceptionUtil.createEvaluateException(ex.getMessage());
+    }
+    catch (InvalidTypeException ex) {
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.type.mismatch"));
+    }
+    catch (IncompatibleThreadStateException e) {
+      throw EvaluateExceptionUtil.createEvaluateException(e);
+    }
+    catch (ClassNotLoadedException ex) {
+      if (!evaluationContext.isAutoLoadClasses()) {
+        throw EvaluateExceptionUtil.createEvaluateException(ex);
+      }
+      final ReferenceType refType;
+      try {
+        refType = setValueRunnable.loadClass(evaluationContext, ex.className());
+        if (refType != null) {
+          //try again
+          setValue(expressionToShow, evaluator, evaluationContext, setValueRunnable);
+        }
+      }
+      catch (InvocationException e) {
+        throw EvaluateExceptionUtil.createEvaluateException(e);
+      }
+      catch (ClassNotLoadedException e) {
+        throw EvaluateExceptionUtil.createEvaluateException(e);
+      }
+      catch (IncompatibleThreadStateException e) {
+        throw EvaluateExceptionUtil.createEvaluateException(e);
+      }
+      catch (InvalidTypeException e) {
+        throw EvaluateExceptionUtil.createEvaluateException(e);
+      }
+      catch (ObjectCollectedException e) {
+        throw EvaluateExceptionUtil.OBJECT_WAS_COLLECTED;
+      }
+    }
+  }
+
+  private void askAndSet(final DebuggerTreeNodeImpl node, final DebuggerContextImpl debuggerContext, final SetValueRunnable setValueRunnable) {
+    ProgressWindowWithNotification progressWindow = new ProgressWindowWithNotification(true, debuggerContext.getProject());
+
+    SuspendContextCommandImpl askSetAction = new DebuggerContextCommandImpl(debuggerContext) {
+      public Priority getPriority() {
+        return Priority.HIGH;
+      }
+
+      public void threadAction() {
+        final NodeDescriptorImpl descriptor = node.getDescriptor();
+        String initialString = "";
+        if (descriptor instanceof ValueDescriptorImpl) {
+          Value currentValue = ((ValueDescriptorImpl) descriptor).getValue();
+          if (currentValue instanceof StringReference) {
+            initialString = DebuggerUtilsEx.getValueOrErrorAsString(debuggerContext.createEvaluationContext(), currentValue);
+            initialString = initialString == null ? "" : "\"" + DebuggerUtilsEx.translateStringValue(initialString) + "\"";
+          }
+          else if (currentValue instanceof PrimitiveValue) {
+            ValueLabelRenderer renderer = ((ValueDescriptorImpl) descriptor).getRenderer(debuggerContext.getDebugProcess());
+            initialString = getDisplayableString((PrimitiveValue) currentValue, renderer instanceof NodeRenderer && HexRenderer.UNIQUE_ID.equals(renderer.getUniqueId()));
+          }
+
+          final String initialString1 = initialString;
+          final Project project = debuggerContext.getProject();
+          DebuggerInvocationUtil.swingInvokeLater(project, new Runnable() {
+            public void run() {
+              showEditor(new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, initialString1), node, debuggerContext, setValueRunnable);
+            }
+          });
+        }
+      }
+    };
+
+    progressWindow.setTitle(DebuggerBundle.message("title.evaluating"));
+    debuggerContext.getDebugProcess().getManagerThread().startProgress(askSetAction, progressWindow);
+  }
+
+  private void showEditor(final TextWithImports initialString,
+                          final DebuggerTreeNodeImpl node,
+                          final DebuggerContextImpl debuggerContext,
+                          final SetValueRunnable setValueRunnable) {
+    final JPanel editorPanel = new JPanel();
+    editorPanel.setLayout(new BoxLayout(editorPanel, BoxLayout.X_AXIS));
+    SimpleColoredComponent label = new SimpleColoredComponent();
+    label.setIcon(node.getIcon());
+    DebuggerTreeRenderer.getDescriptorTitle(debuggerContext, node.getDescriptor()).appendToComponent(label);
+    editorPanel.add(label);
+
+    final DebuggerExpressionComboBox comboBox = new DebuggerExpressionComboBox(
+      debuggerContext.getProject(),
+      PositionUtil.getContextElement(debuggerContext),
+      "setValue", DefaultCodeFragmentFactory.getInstance());
+    comboBox.setText(initialString);
+    comboBox.selectAll();
+    editorPanel.add(comboBox);
+
+    final DebuggerTreeInplaceEditor editor = new DebuggerTreeInplaceEditor(node) {
+      public JComponent createInplaceEditorComponent() {
+        return editorPanel;
+      }
+
+      public JComponent getPreferredFocusedComponent() {
+        return comboBox;
+      }
+
+      public Editor getEditor() {
+        return comboBox.getEditor();
+      }
+
+      public JComponent getEditorComponent() {
+        return comboBox.getEditorComponent();
+      }
+
+      private void flushValue() {
+        Editor editor = getEditor();
+        if(editor == null) {
+          return;
+        }
+
+        final TextWithImports text = comboBox.getText();
+
+        PsiFile psiFile = PsiDocumentManager.getInstance(debuggerContext.getProject()).getPsiFile(editor.getDocument());
+
+        final ProgressWindowWithNotification progressWindow = new ProgressWindowWithNotification(true, getProject());
+        EditorEvaluationCommand evaluationCommand = new EditorEvaluationCommand(getEditor(), psiFile, debuggerContext, progressWindow) {
+          public void threadAction() {
+            try {
+              evaluate();
+            }
+            catch(EvaluateException e) {
+              progressWindow.cancel();
+            }
+            catch(ProcessCanceledException e) {
+              progressWindow.cancel();
+            }
+            finally{
+              if (!progressWindow.isCanceled()) {
+                DebuggerInvocationUtil.swingInvokeLater(debuggerContext.getProject(), new Runnable() {
+                  public void run() {
+                    comboBox.addRecent(text);
+                    cancelEditing();
+                  }
+                });
+              }
+            }
+          }
+
+          protected Object evaluate(final EvaluationContextImpl evaluationContext) throws EvaluateException {
+            ExpressionEvaluator evaluator = DebuggerInvocationUtil.commitAndRunReadAction(evaluationContext.getProject(), new com.intellij.debugger.EvaluatingComputable<ExpressionEvaluator>() {
+              public ExpressionEvaluator compute() throws EvaluateException {
+                return EvaluatorBuilderImpl.build(text, ContextUtil.getContextElement(evaluationContext), ContextUtil.getSourcePosition(evaluationContext));
+              }
+            });
+
+            SetValueAction.setValue(text.getText(), evaluator, evaluationContext, new SetValueRunnable() {
+              public void setValue(EvaluationContextImpl evaluationContext, Value newValue) throws ClassNotLoadedException,
+                                                                                               InvalidTypeException,
+                                                                                               EvaluateException,
+                                                                                               IncompatibleThreadStateException {
+                if(!progressWindow.isCanceled()) {
+                  setValueRunnable.setValue(evaluationContext, newValue);
+                  node.calcValue();
+                }
+              }
+
+              public ReferenceType loadClass(EvaluationContextImpl evaluationContext, String className) throws InvocationException,
+                                                                                                           ClassNotLoadedException,
+                                                                                                           EvaluateException,
+                                                                                                           IncompatibleThreadStateException,
+                                                                                                           InvalidTypeException {
+                return setValueRunnable.loadClass(evaluationContext, className);
+              }
+            });
+
+            return null;
+          }
+        };
+
+        progressWindow.addListener(new ProgressIndicatorListenerAdapter() {
+          //should return whether to stop processing
+          public void stopped() {
+            if(!progressWindow.isCanceled()) {
+              IJSwingUtilities.invoke(new Runnable() {
+                public void run() {
+                  cancelEditing();
+                }
+              });
+            }
+          }
+
+
+        });
+
+        progressWindow.setTitle(DebuggerBundle.message("progress.set.value"));
+        debuggerContext.getDebugProcess().getManagerThread().startProgress(evaluationCommand, progressWindow);
+      }
+
+      public void cancelEditing() {
+        try {
+          super.cancelEditing();
+        }
+        finally {
+          comboBox.dispose();
+        }
+      }
+
+      public void doOKAction() {
+        try {
+          flushValue();
+        }
+        finally {
+          comboBox.dispose();
+        }
+      }
+
+    };
+
+    final DebuggerStateManager stateManager = DebuggerManagerEx.getInstanceEx(debuggerContext.getProject()).getContextManager();
+
+    stateManager.addListener(new DebuggerContextListener() {
+      public void changeEvent(DebuggerContextImpl newContext, int event) {
+        stateManager.removeListener(this);
+        editor.cancelEditing();
+      }
+    });
+
+    node.getTree().hideTooltip();
+
+    editor.show();
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  private static String getDisplayableString(PrimitiveValue value, boolean showAsHex) {
+    if (value instanceof CharValue) {
+      long longValue = value.longValue();
+      return showAsHex ? "0x" + Long.toHexString(longValue).toUpperCase() : Long.toString(longValue);
+    }
+    if (value instanceof ByteValue) {
+      byte val = value.byteValue();
+      String strValue = Integer.toHexString(val).toUpperCase();
+      if (strValue.length() > 2) {
+        strValue = strValue.substring(strValue.length() - 2);
+      }
+      return showAsHex ? "0x" + strValue : value.toString();
+    }
+    if (value instanceof ShortValue) {
+      short val = value.shortValue();
+      String strValue = Integer.toHexString(val).toUpperCase();
+      if (strValue.length() > 4) {
+        strValue = strValue.substring(strValue.length() - 4);
+      }
+      return showAsHex ? "0x" + strValue : value.toString();
+    }
+    if (value instanceof IntegerValue) {
+      int val = value.intValue();
+      return showAsHex ? "0x" + Integer.toHexString(val).toUpperCase() : value.toString();
+    }
+    if (value instanceof LongValue) {
+      long val = value.longValue();
+      return showAsHex ? "0x" + Long.toHexString(val).toUpperCase() + "L" : value.toString() + "L";
+    }
+    return DebuggerUtilsEx.translateStringValue(value.toString());
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/ShowExecutionPointActionHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/ShowExecutionPointActionHandler.java
new file mode 100644
index 0000000..6dc22d3
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/ShowExecutionPointActionHandler.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.project.Project;
+import com.intellij.xdebugger.impl.actions.DebuggerActionHandler;
+import org.jetbrains.annotations.NotNull;
+
+public class ShowExecutionPointActionHandler extends DebuggerActionHandler {
+  public void perform(@NotNull final Project project, final AnActionEvent event) {
+    (DebuggerManagerEx.getInstanceEx(project)).getContext().getDebuggerSession().showExecutionPoint();
+  }
+
+  public boolean isEnabled(@NotNull final Project project, final AnActionEvent event) {
+    DebuggerSession debuggerSession = (DebuggerManagerEx.getInstanceEx(project)).getContext().getDebuggerSession();
+    return debuggerSession != null && debuggerSession.isPaused() &&
+           debuggerSession.getContextManager().getContext().getSuspendContext().getThread() != null;
+  }
+}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/ShowFrameAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/ShowFrameAction.java
new file mode 100644
index 0000000..6b1bf1f
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/ShowFrameAction.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerStateManager;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.debugger.ui.DebuggerPanelsManager;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.DataConstants;
+import com.intellij.openapi.project.Project;
+
+/**
+ * User: lex
+ * Date: Sep 26, 2003
+ * Time: 7:45:21 PM
+ */
+public class ShowFrameAction extends GotoFrameSourceAction {
+  public void actionPerformed(AnActionEvent e) {
+    super.actionPerformed(e);
+    DebuggerStateManager stateManager = getContextManager(e.getDataContext());
+    DebuggerContextImpl context = stateManager.getContext();
+
+    if(context != null) {
+      DebuggerPanelsManager.getInstance(context.getProject()).showFramePanel();
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/StepIntoActionHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/StepIntoActionHandler.java
new file mode 100644
index 0000000..e1e07ec
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/StepIntoActionHandler.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.project.Project;
+import org.jetbrains.annotations.NotNull;
+
+public class StepIntoActionHandler extends AbstractSteppingActionHandler {
+  public void perform(@NotNull final Project project, AnActionEvent e) {
+    final DebuggerSession session = getSession(project);
+    if (session != null) {
+      session.stepInto(false, null);
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/StepOutActionHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/StepOutActionHandler.java
new file mode 100644
index 0000000..161c649
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/StepOutActionHandler.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.project.Project;
+import org.jetbrains.annotations.NotNull;
+
+public class StepOutActionHandler extends AbstractSteppingActionHandler {
+  public void perform(@NotNull final Project project, AnActionEvent e) {
+    final DebuggerSession session = getSession(project);
+    if (session != null) {
+      session.stepOut();
+    }
+  }
+}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/StepOverActionHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/StepOverActionHandler.java
new file mode 100644
index 0000000..bd53245
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/StepOverActionHandler.java
@@ -0,0 +1,31 @@
+
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.project.Project;
+import org.jetbrains.annotations.NotNull;
+
+public class StepOverActionHandler extends AbstractSteppingActionHandler {
+  public void perform(@NotNull final Project project, AnActionEvent e) {
+    final DebuggerSession session = getSession(project);
+    if (session != null) {
+      session.stepOver(false);
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/ThreadDumpAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/ThreadDumpAction.java
new file mode 100644
index 0000000..a1ddd95
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/ThreadDumpAction.java
@@ -0,0 +1,323 @@
+/*
+ * Copyright 2000-2010 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.
+ */
+
+/**
+ * class ExportThreadsAction
+ * @author Eugene Zhuravlev
+ * @author Sascha Weinreuter
+ */
+package com.intellij.debugger.actions;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.events.DebuggerCommandImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
+import com.intellij.debugger.ui.DebuggerPanelsManager;
+import com.intellij.debugger.ui.DebuggerSessionTab;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.PlatformDataKeys;
+import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.ModalityState;
+import com.intellij.openapi.project.Project;
+import com.intellij.unscramble.ThreadDumpParser;
+import com.intellij.unscramble.ThreadState;
+import com.intellij.util.SmartList;
+import com.sun.jdi.*;
+import gnu.trove.TIntObjectHashMap;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ThreadDumpAction extends AnAction implements AnAction.TransparentUpdate {
+
+  public void actionPerformed(AnActionEvent e) {
+    final Project project = PlatformDataKeys.PROJECT.getData(e.getDataContext());
+    if (project == null) {
+      return;
+    }
+    DebuggerContextImpl context = (DebuggerManagerEx.getInstanceEx(project)).getContext();
+
+    final DebuggerSession session = context.getDebuggerSession();
+    if(session != null && session.isAttached()) {
+      final DebugProcessImpl process = context.getDebugProcess();
+      process.getManagerThread().invoke(new DebuggerCommandImpl() {
+        protected void action() throws Exception {
+          final VirtualMachineProxyImpl vm = process.getVirtualMachineProxy();
+          vm.suspend();
+          try {
+            final List<ThreadState> threads = buildThreadStates(vm);
+            ApplicationManager.getApplication().invokeLater(new Runnable() {
+              public void run() {
+                final DebuggerSessionTab sessionTab = DebuggerPanelsManager.getInstance(project).getSessionTab();
+                if (sessionTab != null) {
+                  sessionTab.addThreadDump(threads);
+                }
+              }
+            }, ModalityState.NON_MODAL);
+          }
+          finally {
+            vm.resume();
+          }
+        }
+      });
+    }
+  }
+
+  private static List<ThreadState> buildThreadStates(VirtualMachineProxyImpl vmProxy) {
+    final List<ThreadReference> threads = vmProxy.getVirtualMachine().allThreads();
+    final List<ThreadState> result = new ArrayList<ThreadState>();
+    final Map<String, ThreadState> nameToThreadMap = new HashMap<String, ThreadState>();
+    final Map<String, String> waitingMap = new HashMap<String, String>(); // key 'waits_for' value
+    for (ThreadReference threadReference : threads) {
+      final StringBuilder buffer = new StringBuilder();
+      boolean hasEmptyStack = true;
+      final int threadStatus = threadReference.status();
+      if (threadStatus == ThreadReference.THREAD_STATUS_ZOMBIE) {
+        continue;
+      }
+      final String threadName = threadName(threadReference);
+      final ThreadState threadState = new ThreadState(threadName, threadStatusToState(threadStatus));
+      nameToThreadMap.put(threadName, threadState);
+      result.add(threadState);
+      threadState.setJavaThreadState(threadStatusToJavaThreadState(threadStatus));
+
+      buffer.append("\"").append(threadName).append("\"");
+      ReferenceType referenceType = threadReference.referenceType();
+      if (referenceType != null) {
+        //noinspection HardCodedStringLiteral
+        Field daemon = referenceType.fieldByName("daemon");
+        if (daemon != null) {
+          Value value = threadReference.getValue(daemon);
+          if (value instanceof BooleanValue && ((BooleanValue)value).booleanValue()) {
+            buffer.append(" ").append(DebuggerBundle.message("threads.export.attribute.label.daemon"));
+            threadState.setDaemon(true);
+          }
+        }
+
+        //noinspection HardCodedStringLiteral
+        Field priority = referenceType.fieldByName("priority");
+        if (priority != null) {
+          Value value = threadReference.getValue(priority);
+          if (value instanceof IntegerValue) {
+            buffer.append(" ").append(DebuggerBundle.message("threads.export.attribute.label.priority", ((IntegerValue)value).intValue()));
+          }
+        }
+
+        Field tid = referenceType.fieldByName("tid");
+        if (tid != null) {
+          Value value = threadReference.getValue(tid);
+          if (value instanceof LongValue) {
+            buffer.append(" ").append(DebuggerBundle.message("threads.export.attribute.label.tid", Long.toHexString(((LongValue)value).longValue())));
+            buffer.append(" nid=NA");
+          }
+        }
+      }
+      //ThreadGroupReference groupReference = threadReference.threadGroup();
+      //if (groupReference != null) {
+      //  buffer.append(", ").append(DebuggerBundle.message("threads.export.attribute.label.group", groupReference.name()));
+      //}
+      final String state = threadState.getState();
+      if (state != null) {
+        buffer.append(" ").append(state);
+      }
+
+      buffer.append("\n  java.lang.Thread.State: ").append(threadState.getJavaThreadState());
+      
+      try {
+        if (vmProxy.canGetOwnedMonitorInfo() && vmProxy.canGetMonitorInfo()) {
+          List<ObjectReference> list = threadReference.ownedMonitors();
+          for (ObjectReference reference : list) {
+            if (!vmProxy.canGetMonitorFrameInfo()) { // java 5 and earlier
+              buffer.append("\n\t ").append(renderLockedObject(reference));
+            }
+            final List<ThreadReference> waiting = reference.waitingThreads();
+            for (ThreadReference thread : waiting) {
+              final String waitingThreadName = threadName(thread);
+              waitingMap.put(waitingThreadName, threadName);
+              buffer.append("\n\t ").append(DebuggerBundle.message("threads.export.attribute.label.blocks.thread", waitingThreadName));
+            }
+          }
+        }
+
+        ObjectReference waitedMonitor = vmProxy.canGetCurrentContendedMonitor() ? threadReference.currentContendedMonitor() : null;
+        if (waitedMonitor != null) {
+          if (vmProxy.canGetMonitorInfo()) {
+            ThreadReference waitedMonitorOwner = waitedMonitor.owningThread();
+            if (waitedMonitorOwner != null) {
+              final String monitorOwningThreadName = threadName(waitedMonitorOwner);
+              waitingMap.put(threadName, monitorOwningThreadName);
+              buffer.append("\n\t ")
+                .append(DebuggerBundle.message("threads.export.attribute.label.waiting.for.thread", monitorOwningThreadName, renderObject(waitedMonitor)));
+            }
+          }
+        }
+
+        final List<StackFrame> frames = threadReference.frames();
+        hasEmptyStack = frames.size() == 0;
+
+        final TIntObjectHashMap<List<ObjectReference>> lockedAt = new TIntObjectHashMap<List<ObjectReference>>();
+        if (vmProxy.canGetMonitorFrameInfo()) {
+          for (MonitorInfo info : threadReference.ownedMonitorsAndFrames()) {
+            final int stackDepth = info.stackDepth();
+            List<ObjectReference> monitors;
+            if ((monitors = lockedAt.get(stackDepth)) == null) {
+              lockedAt.put(stackDepth, monitors = new SmartList<ObjectReference>());
+            }
+            monitors.add(info.monitor());
+          }
+        }
+
+        for (int i = 0, framesSize = frames.size(); i < framesSize; i++) {
+          final StackFrame stackFrame = frames.get(i);
+          try {
+            final Location location = stackFrame.location();
+            buffer.append("\n\t  ").append(renderLocation(location));
+
+            final List<ObjectReference> monitors = lockedAt.get(i);
+            if (monitors != null) {
+              for (ObjectReference monitor : monitors) {
+                buffer.append("\n\t  - ").append(renderLockedObject(monitor));
+              }
+            }
+          }
+          catch (InvalidStackFrameException e) {
+            buffer.append("\n\t  Invalid stack frame: ").append(e.getMessage());
+          }
+        }
+      }
+      catch (IncompatibleThreadStateException e) {
+        buffer.append("\n\t ").append(DebuggerBundle.message("threads.export.attribute.error.incompatible.state"));
+      }
+      threadState.setStackTrace(buffer.toString(), hasEmptyStack);
+      ThreadDumpParser.inferThreadStateDetail(threadState);
+    }
+
+    for (String waiting : waitingMap.keySet()) {
+      final ThreadState waitingThread = nameToThreadMap.get(waiting);
+      final ThreadState awaitedThread = nameToThreadMap.get(waitingMap.get(waiting));
+      awaitedThread.addWaitingThread(waitingThread);
+    }
+
+    // detect simple deadlocks
+    for (ThreadState thread : result) {
+      for (ThreadState awaitingThread : thread.getAwaitingThreads()) {
+        if (awaitingThread.isAwaitedBy(thread)) {
+          thread.addDeadlockedThread(awaitingThread);
+          awaitingThread.addDeadlockedThread(thread);
+        }
+      }
+    }
+
+    ThreadDumpParser.sortThreads(result);
+    return result;
+  }
+
+  private static String renderLockedObject(ObjectReference monitor) {
+    return DebuggerBundle.message("threads.export.attribute.label.locked", renderObject(monitor));
+  }
+
+  public static String renderObject(ObjectReference monitor) {
+    String monitorTypeName;
+    try {
+      monitorTypeName = monitor.referenceType().name();
+    }
+    catch (Throwable e) {
+      monitorTypeName = "Error getting object type: '" + e.getMessage() + "'";
+    }
+    return DebuggerBundle.message("threads.export.attribute.label.object-id", Long.toHexString(monitor.uniqueID()), monitorTypeName);
+  }
+
+  private static String threadStatusToJavaThreadState(int status) {
+    switch (status) {
+      case ThreadReference.THREAD_STATUS_MONITOR:
+        return Thread.State.BLOCKED.name();
+      case ThreadReference.THREAD_STATUS_NOT_STARTED:
+        return Thread.State.NEW.name();
+      case ThreadReference.THREAD_STATUS_RUNNING:
+        return Thread.State.RUNNABLE.name();
+      case ThreadReference.THREAD_STATUS_SLEEPING:
+        return Thread.State.TIMED_WAITING.name();
+      case ThreadReference.THREAD_STATUS_WAIT:
+        return Thread.State.WAITING.name();
+      case ThreadReference.THREAD_STATUS_ZOMBIE:
+        return Thread.State.TERMINATED.name();
+      case ThreadReference.THREAD_STATUS_UNKNOWN:
+        return "unknown";
+      default:
+        return "undefined";
+    }
+  }
+
+  private static String threadStatusToState(int status) {
+    switch (status) {
+      case ThreadReference.THREAD_STATUS_MONITOR:
+        return "waiting for monitor entry";
+      case ThreadReference.THREAD_STATUS_NOT_STARTED:
+        return "not started";
+      case ThreadReference.THREAD_STATUS_RUNNING:
+        return "runnable";
+      case ThreadReference.THREAD_STATUS_SLEEPING:
+        return "sleeping";
+      case ThreadReference.THREAD_STATUS_WAIT:
+        return "waiting";
+      case ThreadReference.THREAD_STATUS_ZOMBIE:
+        return "zombie";
+      case ThreadReference.THREAD_STATUS_UNKNOWN:
+        return "unknown";
+      default:
+        return "undefined";
+    }
+  }
+
+  public static String renderLocation(final Location location) {
+    String sourceName;
+    try {
+      sourceName = location.sourceName();
+    }
+    catch (Throwable e) {
+      sourceName = "Unknown Source";
+    }
+    return DebuggerBundle.message(
+        "export.threads.stackframe.format",
+        location.declaringType().name() + "." + location.method().name(),
+        sourceName,
+        location.lineNumber()
+    );
+  }
+
+  private static String threadName(ThreadReference threadReference) {
+    return threadReference.name() + "@" + threadReference.uniqueID();
+  }
+
+
+  public void update(AnActionEvent event){
+    Presentation presentation = event.getPresentation();
+    Project project = PlatformDataKeys.PROJECT.getData(event.getDataContext());
+    if (project == null) {
+      presentation.setEnabled(false);
+      return;
+    }
+    DebuggerSession debuggerSession = (DebuggerManagerEx.getInstanceEx(project)).getContext().getDebuggerSession();
+    presentation.setEnabled(debuggerSession != null && debuggerSession.isAttached());
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/ThrowDebugExceptionAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/ThrowDebugExceptionAction.java
new file mode 100644
index 0000000..a7c244c
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/ThrowDebugExceptionAction.java
@@ -0,0 +1,33 @@
+
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.debugger.DebugException;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.project.DumbAware;
+
+public class ThrowDebugExceptionAction extends AnAction implements DumbAware {
+
+  public void actionPerformed(AnActionEvent event) {
+    try{
+      throw new DebugException();
+    }
+    catch(DebugException e){
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/ToggleBreakpointEnabledAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/ToggleBreakpointEnabledAction.java
new file mode 100644
index 0000000..a3f395b
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/ToggleBreakpointEnabledAction.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.engine.DebuggerUtils;
+import com.intellij.debugger.ui.breakpoints.Breakpoint;
+import com.intellij.debugger.ui.breakpoints.BreakpointManager;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.PlatformDataKeys;
+import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.fileEditor.FileEditorManager;
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.fileTypes.FileTypeManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiFile;
+import org.jetbrains.annotations.Nullable;
+
+public class ToggleBreakpointEnabledAction extends AnAction {
+
+  public void actionPerformed(AnActionEvent e) {
+    final Project project = e.getData(PlatformDataKeys.PROJECT);
+    Breakpoint breakpoint = findBreakpoint(project);
+    if (breakpoint != null) {
+      final BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(project).getBreakpointManager();
+      breakpointManager.setBreakpointEnabled(breakpoint, !breakpoint.ENABLED);
+    }
+  }
+
+  @Nullable
+  private static Breakpoint findBreakpoint(final Project project) {
+    Editor editor = FileEditorManager.getInstance(project).getSelectedTextEditor();
+    if(editor == null) {
+      return null;
+    }
+    BreakpointManager manager = DebuggerManagerEx.getInstanceEx(project).getBreakpointManager();
+    int offset = editor.getCaretModel().getOffset();
+    return manager.findBreakpoint(editor.getDocument(), offset, null);
+  }
+
+  public void update(AnActionEvent event){
+    final Presentation presentation = event.getPresentation();
+    Project project = event.getData(PlatformDataKeys.PROJECT);
+    if (project == null) {
+      presentation.setEnabled(false);
+      return;
+    }
+
+    Editor editor = FileEditorManager.getInstance(project).getSelectedTextEditor();
+    if (editor == null) {
+      presentation.setEnabled(false);
+      return;
+    }
+    PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
+    if (file == null) {
+      presentation.setEnabled(false);
+      return;
+    }
+
+    FileTypeManager fileTypeManager = FileTypeManager.getInstance();
+    final VirtualFile virtualFile = file.getVirtualFile();
+    FileType fileType = virtualFile != null ? virtualFile.getFileType() : null;
+    if (DebuggerUtils.supportsJVMDebugging(fileType) || DebuggerUtils.supportsJVMDebugging(file)) {
+      Breakpoint breakpoint = findBreakpoint(project);
+      if (breakpoint == null) {
+        presentation.setEnabled(false);
+        return;
+      }
+      presentation.setEnabled(true);
+    }
+    else {
+      presentation.setEnabled(false);
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/ToggleFieldBreakpointAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/ToggleFieldBreakpointAction.java
new file mode 100644
index 0000000..0247790
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/ToggleFieldBreakpointAction.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.InstanceFilter;
+import com.intellij.debugger.SourcePosition;
+import com.intellij.debugger.engine.requests.RequestManagerImpl;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.ui.breakpoints.Breakpoint;
+import com.intellij.debugger.ui.breakpoints.BreakpointManager;
+import com.intellij.debugger.ui.breakpoints.FieldBreakpoint;
+import com.intellij.debugger.ui.impl.watch.DebuggerTree;
+import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
+import com.intellij.debugger.ui.impl.watch.FieldDescriptorImpl;
+import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.fileEditor.FileEditorManager;
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.fileTypes.FileTypeManager;
+import com.intellij.openapi.fileTypes.StdFileTypes;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.*;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.sun.jdi.Field;
+import com.sun.jdi.ObjectReference;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * User: lex
+ * Date: Sep 4, 2003
+ * Time: 8:59:30 PM
+ */
+public class ToggleFieldBreakpointAction extends AnAction {
+
+  public void actionPerformed(AnActionEvent e) {
+    Project project = e.getData(PlatformDataKeys.PROJECT);
+    if (project == null) {
+      return;
+    }
+    final SourcePosition place = getPlace(e);
+
+    if(place != null) {
+      Document document = PsiDocumentManager.getInstance(project).getDocument(place.getFile());
+      if (document != null) {
+        DebuggerManagerEx debuggerManager = DebuggerManagerEx.getInstanceEx(project);
+        BreakpointManager manager = debuggerManager.getBreakpointManager();
+        final int offset = place.getOffset();
+        final Breakpoint breakpoint = offset >= 0? manager.findBreakpoint(document, offset, FieldBreakpoint.CATEGORY) : null;
+
+        if(breakpoint == null) {
+          FieldBreakpoint fieldBreakpoint = manager.addFieldBreakpoint(document, offset);
+          if (fieldBreakpoint != null) {
+            if(DebuggerAction.isContextView(e)) {
+              final DebuggerTreeNodeImpl selectedNode = DebuggerAction.getSelectedNode(e.getDataContext());
+              if (selectedNode != null && selectedNode.getDescriptor() instanceof FieldDescriptorImpl) {
+                ObjectReference object = ((FieldDescriptorImpl)selectedNode.getDescriptor()).getObject();
+                if(object != null) {
+                  long id = object.uniqueID();
+                  InstanceFilter[] instanceFilters = new InstanceFilter[] { InstanceFilter.create(Long.toString(id))};
+                  fieldBreakpoint.setInstanceFilters(instanceFilters);
+                  fieldBreakpoint.INSTANCE_FILTERS_ENABLED = true;
+                }
+              }
+            }
+
+            RequestManagerImpl.createRequests(fieldBreakpoint);
+
+            manager.editBreakpoint(fieldBreakpoint, PlatformDataKeys.EDITOR.getData(e.getDataContext()));
+          }
+        }
+        else {
+          manager.removeBreakpoint(breakpoint);
+        }
+      }
+    }
+  }
+
+  public void update(AnActionEvent event){
+    SourcePosition place = getPlace(event);
+    boolean toEnable = place != null;
+
+    Presentation presentation = event.getPresentation();
+    if(ActionPlaces.PROJECT_VIEW_POPUP.equals(event.getPlace()) ||
+       ActionPlaces.STRUCTURE_VIEW_POPUP.equals(event.getPlace()) ||
+       ActionPlaces.FAVORITES_VIEW_POPUP.equals(event.getPlace())) {
+      presentation.setVisible(toEnable);
+    }
+    else if(DebuggerAction.isContextView(event)) {
+      presentation.setText(DebuggerBundle.message("action.add.field.watchpoint.text"));
+      Project project = event.getData(PlatformDataKeys.PROJECT);
+      if(project != null && place != null) {
+        Document document = PsiDocumentManager.getInstance(project).getDocument(place.getFile());
+        if (document != null) {
+          final int offset = place.getOffset();
+          final BreakpointManager breakpointManager = (DebuggerManagerEx.getInstanceEx(project)).getBreakpointManager();
+          final Breakpoint fieldBreakpoint = offset >= 0 ? breakpointManager.findBreakpoint(document, offset, FieldBreakpoint.CATEGORY) : null;
+          if (fieldBreakpoint != null) {
+            presentation.setEnabled(false);
+            return;
+          }
+        }
+      }
+    }
+    presentation.setVisible(toEnable);
+  }
+
+  @Nullable
+  public static SourcePosition getPlace(AnActionEvent event) {
+    final DataContext dataContext = event.getDataContext();
+    Project project = event.getData(PlatformDataKeys.PROJECT);
+    if(project == null) {
+      return null;
+    }
+    if (ActionPlaces.PROJECT_VIEW_POPUP.equals(event.getPlace()) ||
+        ActionPlaces.STRUCTURE_VIEW_POPUP.equals(event.getPlace()) ||
+        ActionPlaces.FAVORITES_VIEW_POPUP.equals(event.getPlace())) {
+      final PsiElement psiElement = event.getData(LangDataKeys.PSI_ELEMENT);
+      if(psiElement instanceof PsiField) {
+        return SourcePosition.createFromElement(psiElement);
+      }
+      return null;
+    }
+
+    final DebuggerTreeNodeImpl selectedNode = DebuggerAction.getSelectedNode(dataContext);
+    if(selectedNode != null && selectedNode.getDescriptor() instanceof FieldDescriptorImpl) {
+      FieldDescriptorImpl descriptor = (FieldDescriptorImpl)selectedNode.getDescriptor();
+      return descriptor.getSourcePosition(project, DebuggerAction.getDebuggerContext(dataContext));
+    }
+
+    if(DebuggerAction.isContextView(event)) {
+      DebuggerTree tree = DebuggerTree.DATA_KEY.getData(dataContext);
+      if(tree != null && tree.getSelectionPath() != null) {
+        DebuggerTreeNodeImpl node = ((DebuggerTreeNodeImpl)tree.getSelectionPath().getLastPathComponent());
+        if(node != null && node.getDescriptor() instanceof FieldDescriptorImpl) {
+          Field field = ((FieldDescriptorImpl)node.getDescriptor()).getField();
+          DebuggerSession session = tree.getDebuggerContext().getDebuggerSession();
+          PsiClass psiClass = DebuggerUtilsEx.findClass(field.declaringType().name(), project, (session != null) ? session.getSearchScope(): GlobalSearchScope.allScope(project));
+          if(psiClass != null) {
+            psiClass = (PsiClass) psiClass.getNavigationElement();
+            final PsiField psiField = psiClass.findFieldByName(field.name(), true);
+            if (psiField != null) {
+              return SourcePosition.createFromElement(psiField);
+            }
+          }
+        }
+      }
+      return null;
+    }
+
+    Editor editor = event.getData(PlatformDataKeys.EDITOR);
+    if(editor == null) {
+      editor = FileEditorManager.getInstance(project).getSelectedTextEditor();
+    }
+    if (editor != null) {
+      final Document document = editor.getDocument();
+      PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(document);
+      if (file != null) {
+        FileTypeManager fileTypeManager = FileTypeManager.getInstance();
+        final VirtualFile virtualFile = file.getVirtualFile();
+        FileType fileType = virtualFile != null ? virtualFile.getFileType() : null;
+        if (StdFileTypes.JAVA == fileType || StdFileTypes.CLASS  == fileType) {
+          final PsiField field = FieldBreakpoint.findField(project, document, editor.getCaretModel().getOffset());
+          if(field != null){
+            return SourcePosition.createFromElement(field);
+          }
+        }
+      }
+    }
+    return null;
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/ToggleLineBreakpointActionHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/ToggleLineBreakpointActionHandler.java
new file mode 100644
index 0000000..5b56156
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/ToggleLineBreakpointActionHandler.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.codeInsight.folding.impl.actions.ExpandRegionAction;
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.engine.DebuggerUtils;
+import com.intellij.debugger.engine.requests.RequestManagerImpl;
+import com.intellij.debugger.ui.breakpoints.Breakpoint;
+import com.intellij.debugger.ui.breakpoints.BreakpointManager;
+import com.intellij.debugger.ui.breakpoints.LineBreakpoint;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.PlatformDataKeys;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.fileEditor.FileEditorManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiManager;
+import com.intellij.xdebugger.impl.actions.DebuggerActionHandler;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class ToggleLineBreakpointActionHandler extends DebuggerActionHandler {
+
+  public boolean isEnabled(@NotNull final Project project, final AnActionEvent event) {
+    PlaceInDocument place = getPlace(project, event);
+    if (place != null) {
+      final Document document = place.getDocument();
+      final int offset = place.getOffset();
+      int line = document.getLineNumber(offset);
+
+      VirtualFile file = FileDocumentManager.getInstance().getFile(document);
+      PsiFile psiFile = PsiManager.getInstance(project).findFile(file);
+      if (DebuggerUtils.supportsJVMDebugging(file.getFileType()) || DebuggerUtils.supportsJVMDebugging(psiFile)) {
+        final BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(project).getBreakpointManager();
+        return breakpointManager.findBreakpoint(document, offset, LineBreakpoint.CATEGORY) != null ||
+                   LineBreakpoint.canAddLineBreakpoint(project, document, line);
+      }
+    }
+
+    return false;
+  }
+
+  public void perform(@NotNull final Project project, final AnActionEvent event) {
+    PlaceInDocument place = getPlace(project, event);
+    if(place == null) {
+      return;
+    }
+
+    ExpandRegionAction.expandRegionAtCaret(project, event.getData(PlatformDataKeys.EDITOR));
+
+    Document document = place.getDocument();
+    int line = document.getLineNumber(place.getOffset());
+
+    DebuggerManagerEx debugManager = DebuggerManagerEx.getInstanceEx(project);
+    if (debugManager == null) {
+      return;
+    }
+    BreakpointManager manager = debugManager.getBreakpointManager();
+    final Breakpoint breakpoint = manager.findBreakpoint(document, place.getOffset(), LineBreakpoint.CATEGORY);
+    if(breakpoint == null) {
+      LineBreakpoint lineBreakpoint = manager.addLineBreakpoint(document, line);
+      if(lineBreakpoint != null) {
+        RequestManagerImpl.createRequests(lineBreakpoint);
+      }
+    } else {
+      manager.removeBreakpoint(breakpoint);
+    }
+  }
+
+  @Nullable
+  private static PlaceInDocument getPlace(@NotNull final Project project, AnActionEvent event) {
+    Editor editor = event.getData(PlatformDataKeys.EDITOR);
+    if(editor == null) {
+      editor = FileEditorManager.getInstance(project).getSelectedTextEditor();
+    }
+    if (editor != null) {
+      final Document document = editor.getDocument();
+      PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(document);
+      if (file != null) {
+        final Editor editor1 = editor;
+        return new PlaceInDocument() {
+          public Document getDocument() {
+            return document;
+          }
+
+          public int getOffset() {
+            return editor1.getCaretModel().getOffset();
+          }
+        };
+      }
+    }
+    return null;
+  }
+}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/ToggleMethodBreakpointAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/ToggleMethodBreakpointAction.java
new file mode 100644
index 0000000..80992e3
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/ToggleMethodBreakpointAction.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/**
+ * class ToggleMethodBreakpointAction
+ * @author Jeka
+ */
+package com.intellij.debugger.actions;
+
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.engine.requests.RequestManagerImpl;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.ui.breakpoints.Breakpoint;
+import com.intellij.debugger.ui.breakpoints.BreakpointManager;
+import com.intellij.debugger.ui.breakpoints.MethodBreakpoint;
+import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.fileEditor.FileEditorManager;
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.fileTypes.StdFileTypes;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiMethod;
+import com.intellij.util.text.CharArrayUtil;
+import org.jetbrains.annotations.Nullable;
+
+public class ToggleMethodBreakpointAction extends AnAction {
+
+  public void update(AnActionEvent event){
+    boolean toEnable = getPlace(event) != null;
+
+    if (ActionPlaces.isPopupPlace(event.getPlace())) {
+      event.getPresentation().setVisible(toEnable);
+    }
+    else {
+      event.getPresentation().setEnabled(toEnable);
+    }
+  }
+
+
+  public void actionPerformed(AnActionEvent e) {
+    Project project = e.getData(PlatformDataKeys.PROJECT);
+    if (project == null) {
+      return;
+    }
+    DebuggerManagerEx debugManager = DebuggerManagerEx.getInstanceEx(project);
+    if (debugManager == null) {
+      return;
+    }
+    final BreakpointManager manager = debugManager.getBreakpointManager();
+    final PlaceInDocument place = getPlace(e);
+    if(place != null) {
+      Breakpoint breakpoint = manager.findBreakpoint(place.getDocument(), place.getOffset(), MethodBreakpoint.CATEGORY);
+      if(breakpoint == null) {
+        final int methodLine = place.getDocument().getLineNumber(place.getOffset());
+        MethodBreakpoint methodBreakpoint = manager.addMethodBreakpoint(place.getDocument(), methodLine);
+        if(methodBreakpoint != null) {
+          RequestManagerImpl.createRequests(methodBreakpoint);
+        }
+      }
+      else {
+        manager.removeBreakpoint(breakpoint);
+      }
+    }
+  }
+
+  @Nullable
+  private static PlaceInDocument getPlace(AnActionEvent event) {
+    final Project project = event.getData(PlatformDataKeys.PROJECT);
+    if(project == null) {
+      return null;
+    }
+
+    PsiElement method = null;
+    Document document = null;
+
+    if (ActionPlaces.PROJECT_VIEW_POPUP.equals(event.getPlace()) ||
+        ActionPlaces.STRUCTURE_VIEW_POPUP.equals(event.getPlace()) ||
+        ActionPlaces.FAVORITES_VIEW_POPUP.equals(event.getPlace()) ||
+        ActionPlaces.NAVIGATION_BAR.equals(event.getPlace())) {
+      final PsiElement psiElement = event.getData(LangDataKeys.PSI_ELEMENT);
+      if(psiElement instanceof PsiMethod) {
+        final PsiFile containingFile = psiElement.getContainingFile();
+        if (containingFile != null) {
+          method = psiElement;
+          document = PsiDocumentManager.getInstance(project).getDocument(containingFile);
+        }
+      }
+    }
+    else {
+      Editor editor = event.getData(PlatformDataKeys.EDITOR);
+      if(editor == null) {
+        editor = FileEditorManager.getInstance(project).getSelectedTextEditor();
+      }
+      if (editor != null) {
+        document = editor.getDocument();
+        PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(document);
+        if (file != null) {
+          final VirtualFile virtualFile = file.getVirtualFile();
+          FileType fileType = virtualFile != null ? virtualFile.getFileType() : null;
+          if (StdFileTypes.JAVA == fileType || StdFileTypes.CLASS  == fileType) {
+            method = findMethod(project, editor);
+          }
+        }
+      }
+    }
+
+    if(method != null) {
+      final PsiElement method1 = method;
+      final Document document1 = document;
+
+      return new PlaceInDocument() {
+        public Document getDocument() {
+          return document1;
+        }
+
+        public int getOffset() {
+          return method1.getTextOffset();
+        }
+      };
+    }
+    return null;
+  }
+
+  @Nullable
+  private static PsiMethod findMethod(Project project, Editor editor) {
+    if (editor == null) {
+      return null;
+    }
+    PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
+    if(psiFile == null) {
+      return null;
+    }
+    final int offset = CharArrayUtil.shiftForward(editor.getDocument().getCharsSequence(), editor.getCaretModel().getOffset(), " \t");
+    return DebuggerUtilsEx.findPsiMethod(psiFile, offset);
+  }
+}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/ViewAsGroup.java b/java/debugger/impl/src/com/intellij/debugger/actions/ViewAsGroup.java
new file mode 100644
index 0000000..6847590
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/ViewAsGroup.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2000-2009 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.debugger.actions;
+
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.events.DebuggerContextCommandImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.settings.NodeRendererSettings;
+import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
+import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl;
+import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl;
+import com.intellij.debugger.ui.tree.render.NodeRenderer;
+import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.DumbAware;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * User: lex
+ * Date: Sep 26, 2003
+ * Time: 11:05:57 PM
+ */
+public class ViewAsGroup extends ActionGroup implements DumbAware {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.actions.ViewAsGroup");
+
+  private AnAction[] myChildren = AnAction.EMPTY_ARRAY;
+
+  public ViewAsGroup() {
+    super(null, true);
+  }
+
+  private static class RendererAction extends ToggleAction {
+    private final NodeRenderer myNodeRenderer;
+
+    public RendererAction(NodeRenderer nodeRenderer) {
+      super(nodeRenderer.getName());
+      myNodeRenderer = nodeRenderer;
+    }
+
+    public boolean isSelected(AnActionEvent e) {
+      DebuggerTreeNodeImpl[] nodes = DebuggerAction.getSelectedNodes(e.getDataContext());
+      if (nodes == null) {
+        return false;
+      }
+      for (DebuggerTreeNodeImpl node : nodes) {
+        if (node.getDescriptor() instanceof ValueDescriptorImpl) {
+          if (((ValueDescriptorImpl)node.getDescriptor()).getLastRenderer() != myNodeRenderer) {
+            return false;
+          }
+        }
+      }
+      return true;
+    }
+
+    public void setSelected(final AnActionEvent e, final boolean state) {
+      final DebuggerContextImpl debuggerContext = DebuggerAction.getDebuggerContext(e.getDataContext());
+      final DebuggerTreeNodeImpl[] nodes = DebuggerAction.getSelectedNodes(e.getDataContext());
+
+      LOG.assertTrue(debuggerContext != null && nodes != null);
+
+      debuggerContext.getDebugProcess().getManagerThread().schedule(new DebuggerContextCommandImpl(debuggerContext) {
+          public void threadAction() {
+            for (final DebuggerTreeNodeImpl node : nodes) {
+              if (node.getDescriptor() instanceof ValueDescriptorImpl) {
+                final ValueDescriptorImpl valueDescriptor = (ValueDescriptorImpl)node.getDescriptor();
+                if (state) {
+                  valueDescriptor.setRenderer(myNodeRenderer);
+                  node.calcRepresentation();
+                }
+              }
+            }
+          }
+        });
+    }
+  }
+
+  public AnAction[] getChildren(@Nullable final AnActionEvent e) {
+    return myChildren;
+  }
+
+  private static AnAction [] calcChildren(DebuggerTreeNodeImpl[] nodes) {
+    List<AnAction> renderers = new ArrayList<AnAction>();
+
+    List<NodeRenderer> allRenderers = NodeRendererSettings.getInstance().getAllRenderers();
+
+    boolean anyValueDescriptor = false;
+
+    for (NodeRenderer nodeRenderer : allRenderers) {
+      boolean allApp = true;
+
+      for (DebuggerTreeNodeImpl node : nodes) {
+        NodeDescriptorImpl descriptor = node.getDescriptor();
+        if (descriptor instanceof ValueDescriptorImpl) {
+          anyValueDescriptor = true;
+          ValueDescriptorImpl valueDescriptor = (ValueDescriptorImpl)descriptor;
+          if (valueDescriptor.isValueValid() && !nodeRenderer.isApplicable(valueDescriptor.getType())) {
+            allApp = false;
+            break;
+          }
+        }
+      }
+
+      if (!anyValueDescriptor) {
+        return AnAction.EMPTY_ARRAY;
+      }
+
+      if (allApp) {
+        renderers.add(new RendererAction(nodeRenderer));
+      }
+    }
+
+    List<AnAction> children = new ArrayList<AnAction>();
+    AnAction[] viewAsActions = ((DefaultActionGroup) ActionManager.getInstance().getAction(DebuggerActions.REPRESENTATION_LIST)).getChildren(null);
+    for (AnAction viewAsAction : viewAsActions) {
+      if (viewAsAction instanceof AutoRendererAction) {
+        if (renderers.size() > 1) {
+          viewAsAction.getTemplatePresentation().setVisible(true);
+          children.add(viewAsAction);
+        }
+      }
+      else {
+        children.add(viewAsAction);
+      }
+    }
+
+    children.add(Separator.getInstance());
+    children.addAll(renderers);
+
+    return children.toArray(new AnAction[children.size()]);
+  }
+
+  public void update(final AnActionEvent event) {
+    if(!DebuggerAction.isFirstStart(event)) {
+      return;
+    }
+
+    final DebuggerContextImpl debuggerContext = DebuggerAction.getDebuggerContext(event.getDataContext());
+    final DebuggerTreeNodeImpl[] selectedNodes = DebuggerAction.getSelectedNodes(event.getDataContext());
+
+    final DebugProcessImpl process = debuggerContext.getDebugProcess();
+    if (process == null) {
+      event.getPresentation().setEnabled(false);
+      return;
+    }
+    
+    process.getManagerThread().schedule(new DebuggerContextCommandImpl(debuggerContext) {
+      public void threadAction() {
+        myChildren = calcChildren(selectedNodes);
+        DebuggerAction.enableAction(event, myChildren.length > 0);
+      }
+    });
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/ViewTextAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/ViewTextAction.java
new file mode 100644
index 0000000..e195ff9
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/ViewTextAction.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2000-2012 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.debugger.actions;
+
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
+import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl;
+import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.EditorFactory;
+import com.intellij.openapi.editor.ex.EditorEx;
+import com.intellij.openapi.editor.impl.DocumentImpl;
+import com.intellij.openapi.fileTypes.FileTypes;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.ui.EditorTextField;
+
+import javax.swing.*;
+import java.awt.*;
+
+/*
+ * @author Jeka
+ */
+public class ViewTextAction extends BaseValueAction {
+  protected void processText(final Project project, final String text, DebuggerTreeNodeImpl node, DebuggerContextImpl debuggerContext) {
+    final NodeDescriptorImpl descriptor = node.getDescriptor();
+    final String labelText = descriptor instanceof ValueDescriptorImpl? ((ValueDescriptorImpl)descriptor).getValueLabel() : null;
+    final MyDialog dialog = new MyDialog(project);
+    dialog.setTitle(labelText != null? "View Text for: " + labelText : "View Text");
+    dialog.setText(text);
+    dialog.show();
+  }
+
+  private static class MyDialog extends DialogWrapper {
+
+    private EditorTextField myTextViewer;
+
+    private MyDialog(Project project) {
+      super(project, false);
+      setModal(false);
+      setCancelButtonText("Close");
+      setCrossClosesWindow(true);
+
+      myTextViewer = new TextViewer(project);
+      init();
+    }
+
+    public void setText(String text) {
+      myTextViewer.setText(text);
+    }
+
+    protected Action[] createActions() {
+      return new Action[] {getCancelAction()};
+    }
+
+    protected String getDimensionServiceKey() {
+      return "#com.intellij.debugger.actions.ViewTextAction";
+    }
+
+    protected JComponent createCenterPanel() {
+      final JPanel panel = new JPanel(new BorderLayout());
+      panel.add(myTextViewer, BorderLayout.CENTER);
+      panel.setPreferredSize(new Dimension(300, 200));
+      return panel;
+    }
+
+  }
+
+
+  private static class TextViewer extends EditorTextField {
+
+    private TextViewer(Project project) {
+      super(createDocument(), project, FileTypes.PLAIN_TEXT, true, false);
+    }
+
+    private static Document createDocument() {
+      final Document document = EditorFactory.getInstance().createDocument("");
+      if (document instanceof DocumentImpl) {
+        ((DocumentImpl)document).setAcceptSlashR(true);
+      }
+      return document;
+    }
+
+    protected EditorEx createEditor() {
+      final EditorEx editor = super.createEditor();
+      editor.setHorizontalScrollbarVisible(true);
+      editor.setVerticalScrollbarVisible(true);
+      editor.setEmbeddedIntoDialogWrapper(true);
+      editor.getComponent().setPreferredSize(null);
+      return editor;
+    }
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/apiAdapters/ConnectionServiceWrapper.java b/java/debugger/impl/src/com/intellij/debugger/apiAdapters/ConnectionServiceWrapper.java
new file mode 100644
index 0000000..150501e
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/apiAdapters/ConnectionServiceWrapper.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2000-2009 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.debugger.apiAdapters;
+
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.SystemInfo;
+import com.intellij.util.ArrayUtil;
+import com.sun.jdi.Bootstrap;
+import com.sun.jdi.VMDisconnectedException;
+import com.sun.jdi.VirtualMachine;
+import com.sun.jdi.VirtualMachineManager;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * @author max
+ */
+public class ConnectionServiceWrapper {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.apiAdapters.ConnectionService");
+
+  private static Class myDelegateClass;
+  private final Object myConnection;
+
+  static {
+    try {
+      //noinspection HardCodedStringLiteral
+      myDelegateClass = SystemInfo.JAVA_VERSION.startsWith("1.4")
+                        ? Class.forName("com.sun.tools.jdi.ConnectionService")
+                        : Class.forName("com.sun.jdi.connect.spi.Connection");
+    }
+    catch (ClassNotFoundException e) {
+      LOG.error(e);
+    }
+  }
+
+  public ConnectionServiceWrapper(final Object connection) {
+    myConnection = connection;
+  }
+
+  public void close() throws IOException {
+    try {
+      //noinspection HardCodedStringLiteral
+      final Method method = myDelegateClass.getMethod("close", ArrayUtil.EMPTY_CLASS_ARRAY);
+      method.invoke(myConnection, ArrayUtil.EMPTY_OBJECT_ARRAY);
+    }
+    catch (NoSuchMethodException e) {
+      LOG.error(e);
+    }
+    catch (IllegalAccessException e) {
+      LOG.error(e);
+    }
+    catch (InvocationTargetException e) {
+      final Throwable cause = e.getCause();
+      if (cause instanceof IOException) {
+        throw (IOException)cause;
+      }
+      LOG.error(e);
+    }
+  }
+
+  public VirtualMachine createVirtualMachine() throws IOException {
+    try {
+      final VirtualMachineManager virtualMachineManager = Bootstrap.virtualMachineManager();
+      //noinspection HardCodedStringLiteral
+      final Method method = virtualMachineManager.getClass().getMethod("createVirtualMachine", new Class[]{myDelegateClass});
+      return (VirtualMachine)method.invoke(virtualMachineManager, new Object[]{myConnection});
+    }
+    catch (NoSuchMethodException e) {
+      LOG.error(e);
+    }
+    catch (IllegalAccessException e) {
+      LOG.error(e);
+    }
+    catch (InvocationTargetException e) {
+      final Throwable cause = e.getCause();
+      if (cause instanceof IOException) {
+        throw (IOException)cause;
+      }
+      if (cause instanceof VMDisconnectedException) {
+        return null; // ignore this one
+      }
+      LOG.error(e);
+    }
+    return null;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/apiAdapters/TransportServiceWrapper.java b/java/debugger/impl/src/com/intellij/debugger/apiAdapters/TransportServiceWrapper.java
new file mode 100644
index 0000000..a464864
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/apiAdapters/TransportServiceWrapper.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2000-2009 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.debugger.apiAdapters;
+
+import com.intellij.execution.ExecutionException;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.SystemInfo;
+import com.intellij.util.ArrayUtil;
+import com.sun.jdi.connect.Transport;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Map;
+import java.util.HashMap;
+
+/**
+ * @author max
+ */
+public class TransportServiceWrapper {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.apiAdapters.TransportService");
+
+  private final Object myDelegateObject;
+  private final Class myDelegateClass;
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  private static final String SOCKET_TRANSPORT_CLASS = SystemInfo.JAVA_VERSION.startsWith("1.4")
+                                                       ? "com.sun.tools.jdi.SocketTransport"
+                                                       : "com.sun.tools.jdi.SocketTransportService";
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  private static final String SHMEM_TRANSPORT_CLASS = SystemInfo.JAVA_VERSION.startsWith("1.4")
+                                                      ? "com.sun.tools.jdi.SharedMemoryTransport"
+                                                      : "com.sun.tools.jdi.SharedMemoryTransportService";
+  
+  private final Map<String, Object> myListenAddresses = new HashMap<String, Object>();
+
+  private TransportServiceWrapper(Class delegateClass) throws NoSuchMethodException,
+                                                      IllegalAccessException,
+                                                      InvocationTargetException,
+                                                      InstantiationException {
+    myDelegateClass = delegateClass;
+    final Constructor constructor = delegateClass.getDeclaredConstructor(ArrayUtil.EMPTY_CLASS_ARRAY);
+    constructor.setAccessible(true);
+    myDelegateObject = constructor.newInstance(ArrayUtil.EMPTY_OBJECT_ARRAY);
+  }
+
+  /**
+   * Applicable if IDEA is run on JDK 1.4.2.x only!
+   * @param transportObj
+   */
+  private TransportServiceWrapper(Transport transportObj) {
+    myDelegateClass = transportObj.getClass();
+    myDelegateObject = transportObj;
+  }
+
+  public ConnectionServiceWrapper attach(final String s) throws IOException {
+    try {
+      // Applicable if IDEA is run on JDK 1.4.2.x only!
+      // in JDK 1.5 the signature of the "attach" method has been changed to "attach(String, long, long)"
+      //noinspection HardCodedStringLiteral
+      final Method method = myDelegateClass.getMethod("attach", new Class[]{String.class});
+      method.setAccessible(true);
+      return new ConnectionServiceWrapper(method.invoke(myDelegateObject, new Object[]{s}));
+    }
+    catch (NoSuchMethodException e) {
+      LOG.error(e);
+    }
+    catch (IllegalAccessException e) {
+      LOG.error(e);
+    }
+    catch (InvocationTargetException e) {
+      final Throwable cause = e.getCause();
+      if (cause instanceof IOException) {
+        throw (IOException)cause;
+      }
+      LOG.error(e);
+    }
+    return null;
+  }
+
+  public String startListening() throws IOException {
+    try {
+      //noinspection HardCodedStringLiteral
+      final Method method = myDelegateClass.getMethod("startListening", ArrayUtil.EMPTY_CLASS_ARRAY);
+      method.setAccessible(true);
+      final Object rv = method.invoke(myDelegateObject, ArrayUtil.EMPTY_OBJECT_ARRAY);
+      // important! do not cast to string cause return types differ in jdk 1.4 and jdk 1.5
+      final String strValue = rv.toString();
+      myListenAddresses.put(strValue, rv);
+      return strValue;
+    }
+    catch (NoSuchMethodException e) {
+      LOG.error(e);
+    }
+    catch (IllegalAccessException e) {
+      LOG.error(e);
+    }
+    catch (InvocationTargetException e) {
+      final Throwable cause = e.getCause();
+      if (cause instanceof IOException) {
+        throw (IOException)cause;
+      }
+      LOG.error(e);
+    }
+    return null;
+  }
+
+  public void stopListening(final String address) throws IOException {
+    try {
+      Object value = myListenAddresses.get(address);
+      if (value == null) {
+        value = address;
+      }
+      Class paramClass = value.getClass();
+      for (Class superClass = paramClass.getSuperclass(); !Object.class.equals(superClass); superClass = superClass.getSuperclass()) {
+        paramClass = superClass;
+      }
+      //noinspection HardCodedStringLiteral
+      final Method method = myDelegateClass.getMethod("stopListening", new Class[] {paramClass});
+      method.setAccessible(true);
+      method.invoke(myDelegateObject, new Object[]{value});
+    }
+    catch (NoSuchMethodException e) {
+      LOG.error(e);
+    }
+    catch (IllegalAccessException e) {
+      LOG.error(e);
+    }
+    catch (InvocationTargetException e) {
+      final Throwable cause = e.getCause();
+      if (cause instanceof IOException) {
+        throw (IOException)cause;
+      }
+      LOG.error(e);
+    }
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  public String transportId() {
+    if (SOCKET_TRANSPORT_CLASS.equals(myDelegateClass.getName())) {
+      return "dt_socket";
+    }
+    else if (SHMEM_TRANSPORT_CLASS.equals(myDelegateClass.getName())) {
+      return "dt_shmem";
+    }
+
+    LOG.error("Unknown serivce");
+    return "<unknown>";
+  }
+
+  public static TransportServiceWrapper getTransportService(boolean forceSocketTransport) throws ExecutionException {
+    TransportServiceWrapper transport;
+    try {
+      try {
+        if (forceSocketTransport) {
+          transport = new TransportServiceWrapper(Class.forName(SOCKET_TRANSPORT_CLASS));
+        }
+        else {
+          transport = new TransportServiceWrapper(Class.forName(SHMEM_TRANSPORT_CLASS));
+        }
+      }
+      catch (UnsatisfiedLinkError e) {
+        transport = new TransportServiceWrapper(Class.forName(SOCKET_TRANSPORT_CLASS));
+      }
+    }
+    catch (Exception e) {
+      throw new ExecutionException(e.getClass().getName() + " : " + e.getMessage());
+    }
+    return transport;
+  }
+
+  /**
+   * Applicable if IDEA is run on JDK 1.4.2.x only!
+   * @param transportObject
+   * @return transport service wrapper
+   */
+  public static TransportServiceWrapper getTransportService(Transport transportObject){
+    return new TransportServiceWrapper(transportObject);
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/codeinsight/JavaWithRuntimeCastSurrounder.java b/java/debugger/impl/src/com/intellij/debugger/codeinsight/JavaWithRuntimeCastSurrounder.java
new file mode 100644
index 0000000..346ff0b
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/codeinsight/JavaWithRuntimeCastSurrounder.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2000-2009 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.debugger.codeinsight;
+
+import com.intellij.codeInsight.CodeInsightBundle;
+import com.intellij.codeInsight.generation.surroundWith.JavaExpressionSurrounder;
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerInvocationUtil;
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.debugger.ui.DebuggerExpressionComboBox;
+import com.intellij.openapi.application.Result;
+import com.intellij.openapi.command.WriteCommandAction;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.ScrollType;
+import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.openapi.progress.util.ProgressWindowWithNotification;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.*;
+import com.intellij.psi.codeStyle.JavaCodeStyleManager;
+import com.intellij.util.IncorrectOperationException;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * User: lex
+ * Date: Jul 17, 2003
+ * Time: 7:51:01 PM
+ */
+public class JavaWithRuntimeCastSurrounder extends JavaExpressionSurrounder {
+
+  public String getTemplateDescription() {
+    return CodeInsightBundle.message("surround.with.runtime.type.template");
+  }
+
+  public boolean isApplicable(PsiExpression expr) {
+    if (!expr.isPhysical()) return false;
+    PsiFile file = expr.getContainingFile();
+    if (!(file instanceof PsiCodeFragment)) return false;
+    if (file.getUserData(DebuggerExpressionComboBox.KEY) == null) {
+      return false;
+    }
+
+    return RuntimeTypeEvaluator.isSubtypeable(expr);
+  }
+
+  public TextRange surroundExpression(Project project, Editor editor, PsiExpression expr) throws IncorrectOperationException {
+    DebuggerContextImpl debuggerContext = (DebuggerManagerEx.getInstanceEx(project)).getContext();
+    DebuggerSession debuggerSession = debuggerContext.getDebuggerSession();
+    if (debuggerSession != null) {
+      final ProgressWindowWithNotification progressWindow = new ProgressWindowWithNotification(true, expr.getProject());
+      SurroundWithCastWorker worker = new SurroundWithCastWorker(editor, expr, debuggerContext, progressWindow);
+      progressWindow.setTitle(DebuggerBundle.message("title.evaluating"));
+      debuggerContext.getDebugProcess().getManagerThread().startProgress(worker, progressWindow);
+    }
+    return null;
+  }
+
+  private class SurroundWithCastWorker extends RuntimeTypeEvaluator {
+    private final Editor myEditor;
+
+    public SurroundWithCastWorker(Editor editor, PsiExpression expression, DebuggerContextImpl context, final ProgressIndicator indicator) {
+      super(editor, expression, context, indicator);
+      myEditor = editor;
+    }
+
+    @Override
+    protected void typeCalculationFinished(@Nullable final PsiClass type) {
+      if (type == null) {
+        return;
+      }
+
+      hold();
+      final Project project = myElement.getProject();
+      DebuggerInvocationUtil.invokeLater(project, new Runnable() {
+        public void run() {
+          new WriteCommandAction(project, CodeInsightBundle.message("command.name.surround.with.runtime.cast")) {
+            protected void run(Result result) throws Throwable {
+              try {
+                PsiElementFactory factory = JavaPsiFacade.getInstance(myElement.getProject()).getElementFactory();
+                PsiParenthesizedExpression parenth =
+                  (PsiParenthesizedExpression)factory.createExpressionFromText("((" + type.getQualifiedName() + ")expr)", null);
+                PsiTypeCastExpression cast = (PsiTypeCastExpression)parenth.getExpression();
+                cast.getOperand().replace(myElement);
+                parenth = (PsiParenthesizedExpression)JavaCodeStyleManager.getInstance(project).shortenClassReferences(parenth);
+                PsiExpression expr = (PsiExpression)myElement.replace(parenth);
+                TextRange range = expr.getTextRange();
+                myEditor.getSelectionModel().setSelection(range.getStartOffset(), range.getEndOffset());
+                myEditor.getCaretModel().moveToOffset(range.getEndOffset());
+                myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
+              }
+              catch (IncorrectOperationException e) {
+                // OK here. Can be caused by invalid type like one for proxy starts with . '.Proxy34'
+              }
+              finally {
+                release();
+              }
+            }
+          }.execute();
+        }
+      }, myProgressIndicator.getModalityState());
+    }
+
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/codeinsight/RuntimeTypeEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/codeinsight/RuntimeTypeEvaluator.java
new file mode 100644
index 0000000..ecb7556
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/codeinsight/RuntimeTypeEvaluator.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2000-2009 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.debugger.codeinsight;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerInvocationUtil;
+import com.intellij.debugger.EvaluatingComputable;
+import com.intellij.debugger.engine.ContextUtil;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilderImpl;
+import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.ui.EditorEvaluationCommand;
+import com.intellij.openapi.application.AccessToken;
+import com.intellij.openapi.application.ReadAction;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.progress.ProcessCanceledException;
+import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.*;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.sun.jdi.ClassType;
+import com.sun.jdi.InterfaceType;
+import com.sun.jdi.Type;
+import com.sun.jdi.Value;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author peter
+ */
+public abstract class RuntimeTypeEvaluator extends EditorEvaluationCommand<PsiClass> {
+  public RuntimeTypeEvaluator(@Nullable Editor editor, PsiElement expression, DebuggerContextImpl context, final ProgressIndicator indicator) {
+    super(editor, expression, context, indicator);
+  }
+
+  public void threadAction() {
+    PsiClass type = null;
+    try {
+      type = evaluate();
+    }
+    catch (ProcessCanceledException ignored) {
+    }
+    catch (EvaluateException ignored) {
+    }
+    finally {
+      typeCalculationFinished(type);
+    }
+  }
+
+  protected abstract void typeCalculationFinished(@Nullable PsiClass type);
+
+  @Nullable
+  protected PsiClass evaluate(final EvaluationContextImpl evaluationContext) throws EvaluateException {
+    final Project project = evaluationContext.getProject();
+
+    ExpressionEvaluator evaluator = DebuggerInvocationUtil.commitAndRunReadAction(project, new EvaluatingComputable<ExpressionEvaluator>() {
+      public ExpressionEvaluator compute() throws EvaluateException {
+        return EvaluatorBuilderImpl.getInstance().build(myElement, ContextUtil.getSourcePosition(evaluationContext));
+      }
+    });
+
+    final Value value = evaluator.evaluate(evaluationContext);
+    if(value != null){
+      return getCastableRuntimeType(project, value);
+    }
+
+    throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.surrounded.expression.null"));
+  }
+
+  public static PsiClass getCastableRuntimeType(Project project, Value value) {
+    Type type = value.type();
+    PsiClass psiClass = findPsiClass(project, type);
+    if (psiClass != null) {
+      return psiClass;
+    }
+
+    if (type instanceof ClassType) {
+      ClassType superclass = ((ClassType)type).superclass();
+      if (superclass != null && !CommonClassNames.JAVA_LANG_OBJECT.equals(superclass.name())) {
+        psiClass = findPsiClass(project, superclass);
+        if (psiClass != null) {
+          return psiClass;
+        }
+      }
+
+      for (InterfaceType interfaceType : ((ClassType)type).interfaces()) {
+        psiClass = findPsiClass(project, interfaceType);
+        if (psiClass != null) {
+          return psiClass;
+        }
+      }
+    }
+    return null;
+  }
+
+  private static PsiClass findPsiClass(Project project, Type type) {
+    AccessToken token = ReadAction.start();
+    try {
+      return JavaPsiFacade.getInstance(project).findClass(type.name().replace('$', '.'), GlobalSearchScope.allScope(project));
+    }
+    finally {
+      token.finish();
+    }
+  }
+
+  public static boolean isSubtypeable(PsiExpression expr) {
+    final PsiType type = expr.getType();
+    if (type instanceof PsiPrimitiveType) {
+      return false;
+    }
+    if (type instanceof PsiClassType) {
+      final PsiClass psiClass = ((PsiClassType)type).resolve();
+      if (psiClass != null && psiClass.hasModifierProperty(PsiModifier.FINAL)) {
+        return false;
+      }
+    }
+    return true;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/CompoundPositionManager.java b/java/debugger/impl/src/com/intellij/debugger/engine/CompoundPositionManager.java
new file mode 100644
index 0000000..49d3cae
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/CompoundPositionManager.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine;
+
+import com.intellij.debugger.NoDataException;
+import com.intellij.debugger.PositionManager;
+import com.intellij.debugger.SourcePosition;
+import com.intellij.debugger.requests.ClassPrepareRequestor;
+import com.intellij.openapi.diagnostic.Logger;
+import com.sun.jdi.Location;
+import com.sun.jdi.ReferenceType;
+import com.sun.jdi.request.ClassPrepareRequest;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class CompoundPositionManager implements PositionManager{
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.CompoundPositionManager");
+  private final ArrayList<PositionManager> myPositionManagers = new ArrayList<PositionManager>();
+
+  public CompoundPositionManager() {
+  }
+
+  public CompoundPositionManager(PositionManager manager) {
+    appendPositionManager(manager);
+  }
+
+  public void appendPositionManager(PositionManager manager) {
+    myPositionManagers.remove(manager);
+    myPositionManagers.add(0, manager);
+  }
+
+  public SourcePosition getSourcePosition(Location location) {
+    for (PositionManager positionManager : myPositionManagers) {
+      try {
+        return positionManager.getSourcePosition(location);
+      }
+      catch (NoDataException ignored) {
+      }
+    }
+    return null;
+  }
+
+  @NotNull
+  public List<ReferenceType> getAllClasses(SourcePosition classPosition) {
+    for (PositionManager positionManager : myPositionManagers) {
+      try {
+        return positionManager.getAllClasses(classPosition);
+      }
+      catch (NoDataException ignored) {
+      }
+    }
+    return Collections.emptyList();
+  }
+
+  @NotNull
+  public List<Location> locationsOfLine(ReferenceType type, SourcePosition position) {
+    for (PositionManager positionManager : myPositionManagers) {
+      try {
+        return positionManager.locationsOfLine(type, position);
+      }
+      catch (NoDataException ignored) {
+      }
+    }
+    return Collections.emptyList();
+  }
+
+  public ClassPrepareRequest createPrepareRequest(ClassPrepareRequestor requestor, SourcePosition position) {
+    for (PositionManager positionManager : myPositionManagers) {
+      try {
+        return positionManager.createPrepareRequest(requestor, position);
+      }
+      catch (NoDataException ignored) {
+      }
+    }
+
+    return null;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/ContextUtil.java b/java/debugger/impl/src/com/intellij/debugger/engine/ContextUtil.java
new file mode 100644
index 0000000..bfd7d05
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/ContextUtil.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine;
+
+import com.intellij.debugger.SourcePosition;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.jdi.StackFrameProxy;
+import com.intellij.debugger.jdi.LocalVariableProxyImpl;
+import com.intellij.debugger.jdi.StackFrameProxyImpl;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.IndexNotReadyException;
+import com.intellij.openapi.util.Comparing;
+import com.intellij.openapi.util.Key;
+import com.intellij.psi.*;
+import com.intellij.util.IncorrectOperationException;
+import com.intellij.util.StringBuilderSpinAllocator;
+import com.sun.jdi.Location;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+
+public class ContextUtil {
+  public static final Key<Boolean> IS_JSP_IMPLICIT = new Key<Boolean>("JspImplicit");
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.impl.PositionUtil");
+
+  @Nullable
+  public static SourcePosition getSourcePosition(final StackFrameContext context) {
+    if (context == null) {
+      return null;
+    }
+    DebugProcessImpl debugProcess = (DebugProcessImpl)context.getDebugProcess();
+    if(debugProcess == null) {
+      return null;
+    }
+    final StackFrameProxy frameProxy = context.getFrameProxy();
+    if(frameProxy == null) {
+      return null;
+    }
+    Location location = null;
+    try {
+      location = frameProxy.location();
+    }
+    catch (Throwable th) {
+      LOG.debug(th);
+    }
+    final CompoundPositionManager positionManager = debugProcess.getPositionManager();
+    if (positionManager == null) {
+      // process already closed
+      return null;
+    }
+    try {
+      return positionManager.getSourcePosition(location);
+    } catch (IndexNotReadyException e) {
+      return null;
+    }
+  }
+
+  @Nullable
+  public static PsiElement getContextElement(final StackFrameContext context) {
+    return getContextElement(context, getSourcePosition(context));
+  }
+
+  @Nullable
+  protected static PsiElement getContextElement(final StackFrameContext context, final SourcePosition position) {
+    if(LOG.isDebugEnabled()) {
+      final SourcePosition sourcePosition = getSourcePosition(context);
+      LOG.assertTrue(Comparing.equal(sourcePosition, position));
+    }
+
+    final PsiElement element = getContextElement(position);
+
+    if(element == null) {
+      return null;
+    }
+
+    final StackFrameProxyImpl frameProxy = (StackFrameProxyImpl)context.getFrameProxy();
+
+    if(frameProxy == null) {
+      return element;
+    }
+
+    final StringBuilder buf = StringBuilderSpinAllocator.alloc();
+    try {
+      List<LocalVariableProxyImpl> list = frameProxy.visibleVariables();
+
+      PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(element.getProject()).getResolveHelper();
+      buf.append('{');
+      for (LocalVariableProxyImpl localVariable : list) {
+        final String varName = localVariable.name();
+        if (resolveHelper.resolveReferencedVariable(varName, element) == null) {
+          buf.append(localVariable.getVariable().typeName()).append(" ").append(varName).append(";");
+        }
+      }
+      buf.append('}');
+
+      if (buf.length() <= 2) {
+        return element;
+      }
+      final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(element.getProject()).getElementFactory();
+      final PsiCodeBlock codeBlockFromText = elementFactory.createCodeBlockFromText(buf.toString(), element);
+
+      final PsiStatement[] statements = codeBlockFromText.getStatements();
+      for (PsiStatement statement : statements) {
+        if (statement instanceof PsiDeclarationStatement) {
+          PsiDeclarationStatement declStatement = (PsiDeclarationStatement)statement;
+          PsiElement[] declaredElements = declStatement.getDeclaredElements();
+          for (PsiElement declaredElement : declaredElements) {
+            declaredElement.putUserData(IS_JSP_IMPLICIT, Boolean.TRUE);
+          }
+        }
+      }
+      return codeBlockFromText;
+    }
+    catch (IncorrectOperationException e) {
+      return element;
+    }
+    catch (EvaluateException e) {
+      return element;
+    }
+    finally {
+      StringBuilderSpinAllocator.dispose(buf);
+    }
+  }
+
+  @Nullable
+  public static PsiElement getContextElement(final SourcePosition position) {
+    return position == null ? null :position.getElementAt();
+  }
+
+  public static boolean isJspImplicit(PsiElement element) {
+    return Boolean.TRUE.equals(element.getUserData(IS_JSP_IMPLICIT));
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessAdapterImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessAdapterImpl.java
new file mode 100644
index 0000000..cc5a975
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessAdapterImpl.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine;
+
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.configurations.RemoteConnection;
+import com.intellij.execution.configurations.RunProfileState;
+import com.sun.jdi.ThreadReference;
+
+/**
+ * @author lex
+ */
+public class DebugProcessAdapterImpl implements DebugProcessListener {
+  //executed in manager thread
+  public final void paused(SuspendContext suspendContext) {
+    paused(((SuspendContextImpl)suspendContext));
+  }
+
+  //executed in manager thread
+  public final void resumed(SuspendContext suspendContext) {
+    resumed(((SuspendContextImpl)suspendContext));
+  }
+
+  //executed in manager thread
+  public final void processDetached(DebugProcess process, boolean closedByUser) {
+    processDetached(((DebugProcessImpl)process), closedByUser);
+  }
+
+  //executed in manager thread
+  public final void processAttached(DebugProcess process) {
+    processAttached(((DebugProcessImpl)process));
+  }
+
+  //executed in manager thread
+  public void connectorIsReady() {
+  }
+
+  public void paused(SuspendContextImpl suspendContext) {
+    //To change body of implemented methods use File | Settings | File Templates.
+  }
+
+  //executed in manager thread
+  public void resumed(SuspendContextImpl suspendContext) {
+    //To change body of implemented methods use File | Settings | File Templates.
+  }
+
+  //executed in manager thread
+  public void processDetached(DebugProcessImpl process, boolean closedByUser) {
+    //To change body of implemented methods use File | Settings | File Templates.
+  }
+
+  //executed in manager thread
+  public void processAttached(DebugProcessImpl process) {
+    //To change body of implemented methods use File | Settings | File Templates.
+  }
+
+  //executed in manager thread
+  public void threadStarted(DebugProcess proc, ThreadReference thread) {
+  }
+
+  //executed in manager thread
+  public void threadStopped(DebugProcess proc, ThreadReference thread) {
+  }
+
+  public void attachException(RunProfileState state, ExecutionException exception, RemoteConnection remoteConnection) {
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java
new file mode 100644
index 0000000..6de56b5
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java
@@ -0,0 +1,487 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerInvocationUtil;
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.engine.events.DebuggerCommandImpl;
+import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
+import com.intellij.debugger.engine.requests.LocatableEventRequestor;
+import com.intellij.debugger.engine.requests.MethodReturnValueWatcher;
+import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
+import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
+import com.intellij.debugger.requests.Requestor;
+import com.intellij.debugger.settings.DebuggerSettings;
+import com.intellij.debugger.ui.DebuggerPanelsManager;
+import com.intellij.debugger.ui.breakpoints.Breakpoint;
+import com.intellij.debugger.ui.breakpoints.BreakpointManager;
+import com.intellij.debugger.ui.breakpoints.LineBreakpoint;
+import com.intellij.execution.configurations.RemoteConnection;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.ModalityState;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.progress.ProcessCanceledException;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.MessageType;
+import com.intellij.openapi.ui.Messages;
+import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.registry.Registry;
+import com.intellij.xdebugger.impl.XDebugSessionImpl;
+import com.sun.jdi.InternalException;
+import com.sun.jdi.ThreadReference;
+import com.sun.jdi.VMDisconnectedException;
+import com.sun.jdi.VirtualMachine;
+import com.sun.jdi.event.*;
+import com.sun.jdi.request.EventRequest;
+import com.sun.jdi.request.EventRequestManager;
+import com.sun.jdi.request.ThreadDeathRequest;
+import com.sun.jdi.request.ThreadStartRequest;
+
+/**
+ * @author lex
+ */
+public class DebugProcessEvents extends DebugProcessImpl {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.DebugProcessEvents");
+  private DebuggerEventThread myEventThread;
+  private final BreakpointManager myBreakpointManager;
+
+  public DebugProcessEvents(Project project) {
+    super(project);
+    myBreakpointManager = DebuggerManagerEx.getInstanceEx(getProject()).getBreakpointManager();
+  }
+
+  protected void commitVM(final VirtualMachine vm) {
+    super.commitVM(vm);
+    if(vm != null) {
+      vmAttached();
+      myEventThread = new DebuggerEventThread();
+      ApplicationManager.getApplication().executeOnPooledThread(myEventThread);
+    }
+  }
+
+  private static void showStatusText(DebugProcessEvents debugProcess,  Event event) {
+    Requestor requestor = debugProcess.getRequestsManager().findRequestor(event.request());
+    Breakpoint breakpoint = null;
+    if(requestor instanceof Breakpoint) {
+      breakpoint = (Breakpoint)requestor;
+    }
+    String text = debugProcess.getEventText(new Pair<Breakpoint, Event>(breakpoint, event));
+    debugProcess.showStatusText(text);
+  }
+
+  public String getEventText(Pair<Breakpoint, Event> descriptor) {
+    String text = "";
+    final Event event = descriptor.getSecond();
+    final Breakpoint breakpoint = descriptor.getFirst();
+    if (event instanceof LocatableEvent) {
+      if (breakpoint instanceof LineBreakpoint && !((LineBreakpoint)breakpoint).isVisible()) {
+        text = DebuggerBundle.message("status.stopped.at.cursor");
+      }
+      else {
+        try {
+          text = breakpoint != null? breakpoint.getEventMessage(((LocatableEvent)event)) : DebuggerBundle.message("status.generic.breakpoint.reached");
+        }
+        catch (InternalException e) {
+          text = DebuggerBundle.message("status.generic.breakpoint.reached");
+        }
+      }
+    }
+    else if (event instanceof VMStartEvent) {
+      text = DebuggerBundle.message("status.process.started");
+    }
+    else if (event instanceof VMDeathEvent) {
+      text = DebuggerBundle.message("status.process.terminated");
+    }
+    else if (event instanceof VMDisconnectEvent) {
+      final RemoteConnection connection = getConnection();
+      final String addressDisplayName = DebuggerBundle.getAddressDisplayName(connection);
+      final String transportName = DebuggerBundle.getTransportName(connection);
+      text = DebuggerBundle.message("status.disconnected", addressDisplayName, transportName);
+    }
+    return text;
+  }
+
+  private class DebuggerEventThread implements Runnable {
+    private final VirtualMachineProxyImpl myVmProxy;
+
+    DebuggerEventThread () {
+      myVmProxy = getVirtualMachineProxy();
+    }
+
+    private boolean myIsStopped = false;
+
+    public synchronized void stopListening() {
+      myIsStopped = true;
+    }
+
+    private synchronized boolean isStopped() {
+      return myIsStopped;
+    }
+
+    public void run() {
+      try {
+        EventQueue eventQueue = myVmProxy.eventQueue();
+        while (!isStopped()) {
+          try {
+            final EventSet eventSet = eventQueue.remove();
+            
+            final boolean methodWatcherActive = myReturnValueWatcher != null && myReturnValueWatcher.isEnabled();
+            int processed = 0;
+            for (EventIterator eventIterator = eventSet.eventIterator(); eventIterator.hasNext();) {
+              final Event event = eventIterator.nextEvent();
+              
+              if (methodWatcherActive) {
+                if (event instanceof MethodExitEvent) {
+                  if (myReturnValueWatcher.processMethodExitEvent((MethodExitEvent)event)) {
+                    processed++;
+                  }
+                  continue;
+                }
+              }
+              if (event instanceof ThreadStartEvent) {
+                processed++;
+                final ThreadReference thread = ((ThreadStartEvent)event).thread();
+                getManagerThread().schedule(new DebuggerCommandImpl() {
+                  protected void action() throws Exception {
+                    getVirtualMachineProxy().threadStarted(thread);
+                    myDebugProcessDispatcher.getMulticaster().threadStarted(DebugProcessEvents.this, thread);
+                  }
+                });
+              }
+              else if (event instanceof ThreadDeathEvent) {
+                processed++;
+                final ThreadReference thread = ((ThreadDeathEvent)event).thread();
+                getManagerThread().schedule(new DebuggerCommandImpl() {
+                  protected void action() throws Exception {
+                    getVirtualMachineProxy().threadStopped(thread);
+                    myDebugProcessDispatcher.getMulticaster().threadStopped(DebugProcessEvents.this, thread);
+                  }
+                });
+              }
+            }
+            
+            if (processed == eventSet.size()) {
+              eventSet.resume();
+              continue;
+            }
+
+            getManagerThread().invokeAndWait(new DebuggerCommandImpl() {
+              protected void action() throws Exception {
+                
+                if (eventSet.suspendPolicy() == EventRequest.SUSPEND_ALL && !enableBreakpointsDuringEvaluation()) {
+                  // check if there is already one request with policy SUSPEND_ALL
+                  for (SuspendContextImpl context : getSuspendManager().getEventContexts()) {
+                    if (context.getSuspendPolicy() == EventRequest.SUSPEND_ALL) {
+                      eventSet.resume();
+                      return;
+                    }
+                  }
+                }
+                
+                final SuspendContextImpl suspendContext = getSuspendManager().pushSuspendContext(eventSet);
+                
+                for (EventIterator eventIterator = eventSet.eventIterator(); eventIterator.hasNext();) {
+                  final Event event = eventIterator.nextEvent();
+
+                  //if (LOG.isDebugEnabled()) {
+                  //  LOG.debug("EVENT : " + event);
+                  //}
+                  try {
+                    if (event instanceof VMStartEvent) {
+                      //Sun WTK fails when J2ME when event set is resumed on VMStartEvent
+                      processVMStartEvent(suspendContext, (VMStartEvent)event);
+                    }
+                    else if (event instanceof VMDeathEvent) {
+                      processVMDeathEvent(suspendContext, event);
+                    }
+                    else if (event instanceof VMDisconnectEvent) {
+                      processVMDeathEvent(suspendContext, event);
+                    }
+                    else if (event instanceof ClassPrepareEvent) {
+                      processClassPrepareEvent(suspendContext, (ClassPrepareEvent)event);
+                    }
+                    //AccessWatchpointEvent, BreakpointEvent, ExceptionEvent, MethodEntryEvent, MethodExitEvent,
+                    //ModificationWatchpointEvent, StepEvent, WatchpointEvent
+                    else if (event instanceof StepEvent) {
+                      processStepEvent(suspendContext, (StepEvent)event);
+                    }
+                    else if (event instanceof LocatableEvent) {
+                      processLocatableEvent(suspendContext, (LocatableEvent)event);
+                    }
+                    else if (event instanceof ClassUnloadEvent) {
+                      processDefaultEvent(suspendContext);
+                    }
+                  }
+                  catch (VMDisconnectedException e) {
+                    LOG.debug(e);
+                  }
+                  catch (InternalException e) {
+                    LOG.info(e);
+                  }
+                  catch (Throwable e) {
+                    LOG.error(e);
+                  }
+                }
+              }
+            });
+
+          }
+          catch (InternalException e) {
+            LOG.debug(e);
+          }
+          catch (InterruptedException e) {
+            throw e;
+          }
+          catch (VMDisconnectedException e) {
+            throw e;
+          }
+          catch (ProcessCanceledException e) {
+            throw e;
+          }
+          catch (Throwable e) {
+            LOG.debug(e);
+          }
+        }
+      }
+      catch (InterruptedException e) {
+        invokeVMDeathEvent();
+      }
+      catch (VMDisconnectedException e) {
+        invokeVMDeathEvent();
+      } finally {
+        Thread.interrupted(); // reset interrupted status
+      }
+    }
+
+    private void invokeVMDeathEvent() {
+      getManagerThread().invokeAndWait(new DebuggerCommandImpl() {
+        protected void action() throws Exception {
+          SuspendContextImpl suspendContext = getSuspendManager().pushSuspendContext(EventRequest.SUSPEND_NONE, 1);
+          processVMDeathEvent(suspendContext, null);
+        }
+      });
+    }
+  }
+
+  private static void preprocessEvent(SuspendContextImpl suspendContext, ThreadReference thread) {
+    ThreadReferenceProxyImpl oldThread = suspendContext.getThread();
+    suspendContext.setThread(thread);
+
+    if(oldThread == null) {
+      //this is the first event in the eventSet that we process
+      suspendContext.getDebugProcess().beforeSuspend(suspendContext);
+    }
+  }
+
+  private void processVMStartEvent(final SuspendContextImpl suspendContext, VMStartEvent event) {
+    preprocessEvent(suspendContext, event.thread());
+
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("enter: processVMStartEvent()");
+    }
+
+    showStatusText(this, event);
+
+    getSuspendManager().voteResume(suspendContext);
+  }
+
+  private void vmAttached() {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    LOG.assertTrue(!isAttached());
+    if(myState.compareAndSet(STATE_INITIAL, STATE_ATTACHED)) {
+      final VirtualMachineProxyImpl machineProxy = getVirtualMachineProxy();
+      final EventRequestManager requestManager = machineProxy.eventRequestManager();
+      
+      if (machineProxy.canGetMethodReturnValues()) {
+        myReturnValueWatcher = new MethodReturnValueWatcher(requestManager);
+      }
+
+      final ThreadStartRequest threadStartRequest = requestManager.createThreadStartRequest();
+      threadStartRequest.setSuspendPolicy(EventRequest.SUSPEND_NONE);
+      threadStartRequest.enable();
+      final ThreadDeathRequest threadDeathRequest = requestManager.createThreadDeathRequest();
+      threadDeathRequest.setSuspendPolicy(EventRequest.SUSPEND_NONE);
+      threadDeathRequest.enable();
+
+      DebuggerManagerEx.getInstanceEx(getProject()).getBreakpointManager().setInitialBreakpointsState();
+      myDebugProcessDispatcher.getMulticaster().processAttached(this);
+
+      final String addressDisplayName = DebuggerBundle.getAddressDisplayName(getConnection());
+      final String transportName = DebuggerBundle.getTransportName(getConnection());
+      showStatusText(DebuggerBundle.message("status.connected", addressDisplayName, transportName));
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("leave: processVMStartEvent()");
+      }
+    }
+  }
+
+  private void processVMDeathEvent(SuspendContextImpl suspendContext, Event event) {
+    try {
+      preprocessEvent(suspendContext, null);
+      cancelRunToCursorBreakpoint();
+    }
+    finally {
+      if (myEventThread != null) {
+        myEventThread.stopListening();
+        myEventThread = null;
+      }
+      closeProcess(false);
+    }
+
+    if(event != null) {
+      showStatusText(this, event);
+    }
+  }
+
+  private void processClassPrepareEvent(SuspendContextImpl suspendContext, ClassPrepareEvent event) {
+    preprocessEvent(suspendContext, event.thread());
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("Class prepared: " + event.referenceType().name());
+    }
+    suspendContext.getDebugProcess().getRequestsManager().processClassPrepared(event);
+
+    getSuspendManager().voteResume(suspendContext);
+  }
+
+  private void processStepEvent(SuspendContextImpl suspendContext, StepEvent event) {
+    final ThreadReference thread = event.thread();
+    //LOG.assertTrue(thread.isSuspended());
+    preprocessEvent(suspendContext, thread);
+
+    //noinspection HardCodedStringLiteral
+    RequestHint hint = (RequestHint)event.request().getProperty("hint");
+
+    deleteStepRequests(event.thread());
+    
+    boolean shouldResume = false;
+
+    final Project project = getProject();
+    if (hint != null) {
+      final int nextStepDepth = hint.getNextStepDepth(suspendContext);
+      if (nextStepDepth != RequestHint.STOP) {
+        final ThreadReferenceProxyImpl threadProxy = suspendContext.getThread();
+        doStep(suspendContext, threadProxy, nextStepDepth, hint);
+        shouldResume = true;
+      }
+
+      if(!shouldResume && hint.isRestoreBreakpoints()) {
+        DebuggerManagerEx.getInstanceEx(project).getBreakpointManager().enableBreakpoints(this);
+      }
+    }
+
+    if(shouldResume) {
+      getSuspendManager().voteResume(suspendContext);
+    }
+    else {
+      showStatusText("");
+      if (myReturnValueWatcher != null) {
+        myReturnValueWatcher.disable();
+      }
+      getSuspendManager().voteSuspend(suspendContext);
+      if (hint != null) {
+        final RequestHint.SmartStepFilter smartStepFilter = hint.getSmartStepFilter();
+        if (smartStepFilter != null && !smartStepFilter.wasMethodExecuted()) {
+          final String message = "Method <b>" + smartStepFilter.getTargetMethodName() + "()</b> has not been called";
+          XDebugSessionImpl.NOTIFICATION_GROUP.createNotification(message, MessageType.INFO).notify(project);
+        }
+      }
+    }
+  }
+
+  private void processLocatableEvent(final SuspendContextImpl suspendContext, final LocatableEvent event) {
+    if (myReturnValueWatcher != null && event instanceof MethodExitEvent) {
+      if (myReturnValueWatcher.processMethodExitEvent(((MethodExitEvent)event))) {
+        return;
+      }
+    }
+
+    ThreadReference thread = event.thread();
+    //LOG.assertTrue(thread.isSuspended());
+    preprocessEvent(suspendContext, thread);
+
+    //we use schedule to allow processing other events during processing this one
+    //this is especially nesessary if a method is breakpoint condition
+    getManagerThread().schedule(new SuspendContextCommandImpl(suspendContext) {
+      public void contextAction() throws Exception {
+        final SuspendManager suspendManager = getSuspendManager();
+        SuspendContextImpl evaluatingContext = SuspendManagerUtil.getEvaluatingContext(suspendManager, getSuspendContext().getThread());
+
+        if (evaluatingContext != null && !enableBreakpointsDuringEvaluation()) {
+          // is inside evaluation, so ignore any breakpoints
+          suspendManager.voteResume(suspendContext);
+          return;
+        }
+
+        final LocatableEventRequestor requestor = (LocatableEventRequestor) getRequestsManager().findRequestor(event.request());
+
+        boolean resumePreferred = requestor != null && DebuggerSettings.SUSPEND_NONE.equals(requestor.getSuspendPolicy());
+        boolean requestHit = false;
+        try {
+          requestHit = (requestor != null) && requestor.processLocatableEvent(this, event);
+        }
+        catch (final LocatableEventRequestor.EventProcessingException ex) {
+          if (LOG.isDebugEnabled()) {
+            LOG.debug(ex.getMessage());
+          }
+          final boolean[] considerRequestHit = new boolean[]{true};
+          DebuggerInvocationUtil.invokeAndWait(getProject(), new Runnable() {
+            public void run() {
+              DebuggerPanelsManager.getInstance(getProject()).toFront(mySession);
+              final String displayName = requestor instanceof Breakpoint? ((Breakpoint)requestor).getDisplayName() : requestor.getClass().getSimpleName();
+              final String message = DebuggerBundle.message("error.evaluating.breakpoint.condition.or.action", displayName, ex.getMessage());
+              considerRequestHit[0] = Messages.showYesNoDialog(getProject(), message, ex.getTitle(), Messages.getQuestionIcon()) == 0;
+            }
+          }, ModalityState.NON_MODAL);
+          requestHit = considerRequestHit[0];
+          resumePreferred = !requestHit;
+        }
+
+        if (requestHit && requestor instanceof Breakpoint) {
+          // if requestor is a breakpoint and this breakpoint was hit, no matter its suspend policy
+          myBreakpointManager.processBreakpointHit((Breakpoint)requestor);
+        }
+
+        if(!requestHit || resumePreferred) {
+          suspendManager.voteResume(suspendContext);
+        }
+        else {
+          if (myReturnValueWatcher != null) {
+            myReturnValueWatcher.disable();
+          }
+          //if (suspendContext.getSuspendPolicy() == EventRequest.SUSPEND_ALL) {
+          //  // there could be explicit resume as a result of call to voteSuspend()
+          //  // e.g. when breakpoint was considered invalid, in that case the filter will be applied _after_
+          //  // resuming and all breakpoints in other threads will be ignored.
+          //  // As resume() implicitly cleares the filter, the filter must be always applied _before_ any resume() action happens
+          //  myBreakpointManager.applyThreadFilter(DebugProcessEvents.this, event.thread());
+          //}
+          suspendManager.voteSuspend(suspendContext);
+          showStatusText(DebugProcessEvents.this, event);
+        }
+      }
+    });
+  }
+
+  private static boolean enableBreakpointsDuringEvaluation() {
+    return Registry.is("debugger.enable.breakpoints.during.evaluation");
+  }
+
+  private void processDefaultEvent(SuspendContextImpl suspendContext) {
+    preprocessEvent(suspendContext, null);
+    getSuspendManager().voteResume(suspendContext);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java
new file mode 100644
index 0000000..3c71e0a
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java
@@ -0,0 +1,1920 @@
+/*
+ * Copyright 2000-2012 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.debugger.engine;
+
+import com.intellij.Patches;
+import com.intellij.debugger.*;
+import com.intellij.debugger.actions.DebuggerActions;
+import com.intellij.debugger.apiAdapters.ConnectionServiceWrapper;
+import com.intellij.debugger.apiAdapters.TransportServiceWrapper;
+import com.intellij.debugger.engine.evaluation.*;
+import com.intellij.debugger.engine.events.DebuggerCommandImpl;
+import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
+import com.intellij.debugger.engine.jdi.ThreadReferenceProxy;
+import com.intellij.debugger.engine.requests.MethodReturnValueWatcher;
+import com.intellij.debugger.engine.requests.RequestManagerImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.impl.PrioritizedTask;
+import com.intellij.debugger.jdi.StackFrameProxyImpl;
+import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
+import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
+import com.intellij.debugger.settings.DebuggerSettings;
+import com.intellij.debugger.settings.NodeRendererSettings;
+import com.intellij.debugger.ui.breakpoints.BreakpointManager;
+import com.intellij.debugger.ui.breakpoints.RunToCursorBreakpoint;
+import com.intellij.debugger.ui.tree.ValueDescriptor;
+import com.intellij.debugger.ui.tree.render.*;
+import com.intellij.execution.CantRunException;
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.ExecutionResult;
+import com.intellij.execution.Executor;
+import com.intellij.execution.configurations.RemoteConnection;
+import com.intellij.execution.configurations.RunProfileState;
+import com.intellij.execution.process.ProcessAdapter;
+import com.intellij.execution.process.ProcessEvent;
+import com.intellij.execution.process.ProcessListener;
+import com.intellij.execution.process.ProcessOutputTypes;
+import com.intellij.execution.runners.ExecutionUtil;
+import com.intellij.execution.runners.ProgramRunner;
+import com.intellij.idea.ActionsBundle;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.extensions.Extensions;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.Messages;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.util.Key;
+import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.Ref;
+import com.intellij.openapi.wm.ToolWindowId;
+import com.intellij.openapi.wm.WindowManager;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.ui.classFilter.ClassFilter;
+import com.intellij.ui.classFilter.DebuggerClassFilterProvider;
+import com.intellij.util.Alarm;
+import com.intellij.util.EventDispatcher;
+import com.intellij.util.StringBuilderSpinAllocator;
+import com.intellij.util.concurrency.Semaphore;
+import com.sun.jdi.*;
+import com.sun.jdi.connect.*;
+import com.sun.jdi.request.EventRequest;
+import com.sun.jdi.request.EventRequestManager;
+import com.sun.jdi.request.StepRequest;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.io.IOException;
+import java.net.UnknownHostException;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public abstract class DebugProcessImpl implements DebugProcess {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.DebugProcessImpl");
+
+  @NonNls private static final String SOCKET_ATTACHING_CONNECTOR_NAME = "com.sun.jdi.SocketAttach";
+  @NonNls private static final String SHMEM_ATTACHING_CONNECTOR_NAME = "com.sun.jdi.SharedMemoryAttach";
+  @NonNls private static final String SOCKET_LISTENING_CONNECTOR_NAME = "com.sun.jdi.SocketListen";
+  @NonNls private static final String SHMEM_LISTENING_CONNECTOR_NAME = "com.sun.jdi.SharedMemoryListen";
+
+  private final Project myProject;
+  private final RequestManagerImpl myRequestManager;
+
+  private VirtualMachineProxyImpl myVirtualMachineProxy = null;
+  protected EventDispatcher<DebugProcessListener> myDebugProcessDispatcher = EventDispatcher.create(DebugProcessListener.class);
+  protected EventDispatcher<EvaluationListener> myEvaluationDispatcher = EventDispatcher.create(EvaluationListener.class);
+
+  private final List<ProcessListener> myProcessListeners = new ArrayList<ProcessListener>();
+
+  protected static final int STATE_INITIAL   = 0;
+  protected static final int STATE_ATTACHED  = 1;
+  protected static final int STATE_DETACHING = 2;
+  protected static final int STATE_DETACHED  = 3;
+  protected final AtomicInteger myState = new AtomicInteger(STATE_INITIAL);
+
+  private ExecutionResult  myExecutionResult;
+  private RemoteConnection myConnection;
+
+  private ConnectionServiceWrapper myConnectionService;
+  private Map<String, Connector.Argument> myArguments;
+
+  private final List<NodeRenderer> myRenderers = new ArrayList<NodeRenderer>();
+  private final Map<Type, NodeRenderer>  myNodeRederersMap = new com.intellij.util.containers.HashMap<Type, NodeRenderer>();
+  private final NodeRendererSettingsListener  mySettingsListener = new NodeRendererSettingsListener() {
+      public void renderersChanged() {
+        myNodeRederersMap.clear();
+        myRenderers.clear();
+        loadRenderers();
+      }
+    };
+
+  private final SuspendManagerImpl mySuspendManager = new SuspendManagerImpl(this);
+  protected CompoundPositionManager myPositionManager = null;
+  private volatile DebuggerManagerThreadImpl myDebuggerManagerThread;
+  private final HashMap myUserData = new HashMap();
+  private static final int LOCAL_START_TIMEOUT = 30000;
+
+  private final Semaphore myWaitFor = new Semaphore();
+  private final AtomicBoolean myBreakpointsMuted = new AtomicBoolean(false);
+  private boolean myIsFailed = false;
+  protected DebuggerSession mySession;
+  @Nullable protected MethodReturnValueWatcher myReturnValueWatcher;
+  private final Disposable myDisposable = Disposer.newDisposable();
+  private final Alarm myStatusUpdateAlarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD, myDisposable);
+
+  /** @noinspection FieldCanBeLocal*/
+  private volatile boolean myDebugProcessStarted = false;
+
+  protected DebugProcessImpl(Project project) {
+    myProject = project;
+    myRequestManager = new RequestManagerImpl(this);
+    NodeRendererSettings.getInstance().addListener(mySettingsListener);
+    loadRenderers();
+  }
+
+  private void loadRenderers() {
+    getManagerThread().invoke(new DebuggerCommandImpl() {
+      protected void action() throws Exception {
+        try {
+          final NodeRendererSettings rendererSettings = NodeRendererSettings.getInstance();
+          for (final NodeRenderer renderer : rendererSettings.getAllRenderers()) {
+            if (renderer.isEnabled()) {
+              myRenderers.add(renderer);
+            }
+          }
+        }
+        finally {
+          DebuggerInvocationUtil.swingInvokeLater(myProject, new Runnable() {
+            public void run() {
+              final DebuggerSession session = mySession;
+              if (session != null && session.isAttached()) {
+                session.refresh(true);
+              }
+            }
+          });
+        }
+      }
+    });
+  }
+
+  @Nullable
+  public Pair<Method, Value> getLastExecutedMethod() {
+    final MethodReturnValueWatcher watcher = myReturnValueWatcher;
+    if (watcher == null) {
+      return null;
+    }
+    final Method method = watcher.getLastExecutedMethod();
+    if (method == null) {
+      return null;
+    }
+    return new Pair<Method, Value>(method, watcher.getLastMethodReturnValue());
+  }
+
+  public void setWatchMethodReturnValuesEnabled(boolean enabled) {
+    final MethodReturnValueWatcher watcher = myReturnValueWatcher;
+    if (watcher != null) {
+      watcher.setFeatureEnabled(enabled);
+    }
+  }
+
+  public boolean isWatchMethodReturnValuesEnabled() {
+    final MethodReturnValueWatcher watcher = myReturnValueWatcher;
+    return watcher != null && watcher.isFeatureEnabled();
+  }
+
+  public boolean canGetMethodReturnValue() {
+    return myReturnValueWatcher != null;
+  }
+
+  public NodeRenderer getAutoRenderer(ValueDescriptor descriptor) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    final Value value = descriptor.getValue();
+    Type type = value != null ? value.type() : null;
+
+    // in case evaluation is not possible, force default renderer
+    if (!DebuggerManagerEx.getInstanceEx(getProject()).getContext().isEvaluationPossible()) {
+      return getDefaultRenderer(type);
+    }
+
+    NodeRenderer renderer = myNodeRederersMap.get(type);
+    if(renderer == null) {
+      for (final NodeRenderer nodeRenderer : myRenderers) {
+        if (nodeRenderer.isApplicable(type)) {
+          renderer = nodeRenderer;
+          break;
+        }
+      }
+      if (renderer == null) {
+        renderer = getDefaultRenderer(type);
+      }
+      myNodeRederersMap.put(type, renderer);
+    }
+
+    return renderer;
+  }
+
+  public static NodeRenderer getDefaultRenderer(Value value) {
+    return getDefaultRenderer(value != null ? value.type() : null);
+  }
+
+  public static NodeRenderer getDefaultRenderer(Type type) {
+    final NodeRendererSettings settings = NodeRendererSettings.getInstance();
+
+    final PrimitiveRenderer primitiveRenderer = settings.getPrimitiveRenderer();
+    if(primitiveRenderer.isApplicable(type)) {
+      return primitiveRenderer;
+    }
+
+    final ArrayRenderer arrayRenderer = settings.getArrayRenderer();
+    if(arrayRenderer.isApplicable(type)) {
+      return arrayRenderer;
+    }
+
+    final ClassRenderer classRenderer = settings.getClassRenderer();
+    LOG.assertTrue(classRenderer.isApplicable(type), type.name());
+    return classRenderer;
+  }
+
+
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  protected void commitVM(VirtualMachine vm) {
+    if (!isInInitialState()) {
+      LOG.error("State is invalid " + myState.get());
+    }
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    myPositionManager = createPositionManager();
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("*******************VM attached******************");
+    }
+    checkVirtualMachineVersion(vm);
+
+    myVirtualMachineProxy = new VirtualMachineProxyImpl(this, vm);
+
+    String trace = System.getProperty("idea.debugger.trace");
+    if (trace != null) {
+      int mask = 0;
+      StringTokenizer tokenizer = new StringTokenizer(trace);
+      while (tokenizer.hasMoreTokens()) {
+        String token = tokenizer.nextToken();
+        if ("SENDS".compareToIgnoreCase(token) == 0) {
+          mask |= VirtualMachine.TRACE_SENDS;
+        }
+        else if ("RAW_SENDS".compareToIgnoreCase(token) == 0) {
+          mask |= 0x01000000;
+        }
+        else if ("RECEIVES".compareToIgnoreCase(token) == 0) {
+          mask |= VirtualMachine.TRACE_RECEIVES;
+        }
+        else if ("RAW_RECEIVES".compareToIgnoreCase(token) == 0) {
+          mask |= 0x02000000;
+        }
+        else if ("EVENTS".compareToIgnoreCase(token) == 0) {
+          mask |= VirtualMachine.TRACE_EVENTS;
+        }
+        else if ("REFTYPES".compareToIgnoreCase(token) == 0) {
+          mask |= VirtualMachine.TRACE_REFTYPES;
+        }
+        else if ("OBJREFS".compareToIgnoreCase(token) == 0) {
+          mask |= VirtualMachine.TRACE_OBJREFS;
+        }
+        else if ("ALL".compareToIgnoreCase(token) == 0) {
+          mask |= VirtualMachine.TRACE_ALL;
+        }
+      }
+
+      vm.setDebugTraceMode(mask);
+    }
+  }
+
+  private void stopConnecting() {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+
+    Map arguments = myArguments;
+    try {
+      if (arguments == null) {
+        return;
+      }
+      if(myConnection.isServerMode()) {
+        ListeningConnector connector = (ListeningConnector)findConnector(SOCKET_LISTENING_CONNECTOR_NAME);
+        if (connector == null) {
+          LOG.error("Cannot find connector: " + SOCKET_LISTENING_CONNECTOR_NAME);
+        }
+        connector.stopListening(arguments);
+      }
+      else {
+        if(myConnectionService != null) {
+          myConnectionService.close();
+        }
+      }
+    }
+    catch (IOException e) {
+      if (LOG.isDebugEnabled()) {
+        LOG.debug(e);
+      }
+    }
+    catch (IllegalConnectorArgumentsException e) {
+      if (LOG.isDebugEnabled()) {
+        LOG.debug(e);
+      }
+    }
+    catch (ExecutionException e) {
+      LOG.error(e);
+    }
+    finally {
+      closeProcess(true);
+    }
+  }
+
+  protected CompoundPositionManager createPositionManager() {
+    return new CompoundPositionManager(new PositionManagerImpl(this));
+  }
+
+  public void printToConsole(final String text) {
+    myExecutionResult.getProcessHandler().notifyTextAvailable(text, ProcessOutputTypes.SYSTEM);
+  }
+
+  /**
+   *
+   * @param suspendContext
+   * @param stepThread
+   * @param depth
+   * @param hint may be null
+   */
+  protected void doStep(final SuspendContextImpl suspendContext, final ThreadReferenceProxyImpl stepThread, int depth, RequestHint hint) {
+    if (stepThread == null) {
+      return;
+    }
+    try {
+      final ThreadReference stepThreadReference = stepThread.getThreadReference();
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("DO_STEP: creating step request for " + stepThreadReference);
+      }
+      deleteStepRequests(stepThreadReference);
+      EventRequestManager requestManager = getVirtualMachineProxy().eventRequestManager();
+      StepRequest stepRequest = requestManager.createStepRequest(stepThreadReference, StepRequest.STEP_LINE, depth);
+      DebuggerSettings settings = DebuggerSettings.getInstance();
+      if (!(hint != null && hint.isIgnoreFilters()) /*&& depth == StepRequest.STEP_INTO*/) {
+        final List<ClassFilter> activeFilters = new ArrayList<ClassFilter>();
+        if (settings.TRACING_FILTERS_ENABLED) {
+          for (ClassFilter filter : settings.getSteppingFilters()) {
+            if (filter.isEnabled()) {
+              activeFilters.add(filter);
+            }
+          }
+        }
+        for (DebuggerClassFilterProvider provider : Extensions.getExtensions(DebuggerClassFilterProvider.EP_NAME)) {
+          for (ClassFilter filter : provider.getFilters()) {
+            if (filter.isEnabled()) {
+              activeFilters.add(filter);
+            }
+          }
+        }
+
+        if (!activeFilters.isEmpty()) {
+          final String currentClassName = getCurrentClassName(stepThread);
+          if (currentClassName == null || !DebuggerUtilsEx.isFiltered(currentClassName, activeFilters)) {
+            // add class filters
+            for (ClassFilter filter : activeFilters) {
+              stepRequest.addClassExclusionFilter(filter.getPattern());
+            }
+          }
+        }
+      }
+
+      // suspend policy to match the suspend policy of the context:
+      // if all threads were suspended, then during stepping all the threads must be suspended
+      // if only event thread were suspended, then only this particular thread must be suspended during stepping
+      stepRequest.setSuspendPolicy(suspendContext.getSuspendPolicy() == EventRequest.SUSPEND_EVENT_THREAD? EventRequest.SUSPEND_EVENT_THREAD : EventRequest.SUSPEND_ALL);
+
+      if (hint != null) {
+        //noinspection HardCodedStringLiteral
+        stepRequest.putProperty("hint", hint);
+      }
+      stepRequest.enable();
+    }
+    catch (ObjectCollectedException ignored) {
+
+    }
+  }
+
+  void deleteStepRequests(@Nullable final ThreadReference stepThread) {
+    EventRequestManager requestManager = getVirtualMachineProxy().eventRequestManager();
+    List<StepRequest> stepRequests = requestManager.stepRequests();
+    if (!stepRequests.isEmpty()) {
+      final List<StepRequest> toDelete = new ArrayList<StepRequest>(stepRequests.size());
+      for (final StepRequest request : stepRequests) {
+        ThreadReference threadReference = request.thread();
+        // [jeka] on attempt to delete a request assigned to a thread with unknown status, a JDWP error occures
+        if (threadReference.status() != ThreadReference.THREAD_STATUS_UNKNOWN && (stepThread == null || stepThread.equals(threadReference))) {
+          toDelete.add(request);
+        }
+      }
+      requestManager.deleteEventRequests(toDelete);
+    }
+  }
+
+  @Nullable
+  private static String getCurrentClassName(ThreadReferenceProxyImpl thread) {
+    try {
+      if (thread != null && thread.frameCount() > 0) {
+        StackFrameProxyImpl stackFrame = thread.frame(0);
+        if (stackFrame != null) {
+          Location location = stackFrame.location();
+          ReferenceType referenceType = location.declaringType();
+          if (referenceType != null) {
+            return referenceType.name();
+          }
+        }
+      }
+    }
+    catch (EvaluateException ignored) {
+    }
+    return null;
+  }
+
+  private VirtualMachine createVirtualMachineInt() throws ExecutionException {
+    try {
+      if (myArguments != null) {
+        throw new IOException(DebuggerBundle.message("error.debugger.already.listening"));
+      }
+
+      final String address = myConnection.getAddress();
+      if (myConnection.isServerMode()) {
+        ListeningConnector connector = (ListeningConnector)findConnector(
+          myConnection.isUseSockets() ? SOCKET_LISTENING_CONNECTOR_NAME : SHMEM_LISTENING_CONNECTOR_NAME);
+        if (connector == null) {
+          throw new CantRunException(DebuggerBundle.message("error.debug.connector.not.found", DebuggerBundle.getTransportName(myConnection)));
+        }
+        myArguments = connector.defaultArguments();
+        if (myArguments == null) {
+          throw new CantRunException(DebuggerBundle.message("error.no.debug.listen.port"));
+        }
+
+        if (address == null) {
+          throw new CantRunException(DebuggerBundle.message("error.no.debug.listen.port"));
+        }
+        // negative port number means the caller leaves to debugger to decide at which hport to listen
+        //noinspection HardCodedStringLiteral
+        final Connector.Argument portArg = myConnection.isUseSockets() ? myArguments.get("port") : myArguments.get("name");
+        if (portArg != null) {
+          portArg.setValue(address);
+        }
+        //noinspection HardCodedStringLiteral
+        final Connector.Argument timeoutArg = myArguments.get("timeout");
+        if (timeoutArg != null) {
+          timeoutArg.setValue("0"); // wait forever
+        }
+        connector.startListening(myArguments);
+        myDebugProcessDispatcher.getMulticaster().connectorIsReady();
+        try {
+          return connector.accept(myArguments);
+        }
+        finally {
+          if(myArguments != null) {
+            try {
+              connector.stopListening(myArguments);
+            }
+            catch (IllegalArgumentException e) {
+              // ignored
+            }
+            catch (IllegalConnectorArgumentsException e) {
+              // ignored
+            }
+          }
+        }
+      }
+      else { // is client mode, should attach to already running process
+        AttachingConnector connector = (AttachingConnector)findConnector(
+          myConnection.isUseSockets() ? SOCKET_ATTACHING_CONNECTOR_NAME : SHMEM_ATTACHING_CONNECTOR_NAME
+        );
+
+        if (connector == null) {
+          throw new CantRunException( DebuggerBundle.message("error.debug.connector.not.found", DebuggerBundle.getTransportName(myConnection)));
+        }
+        myArguments = connector.defaultArguments();
+        if (myConnection.isUseSockets()) {
+          //noinspection HardCodedStringLiteral
+          final Connector.Argument hostnameArg = myArguments.get("hostname");
+          if (hostnameArg != null && myConnection.getHostName() != null) {
+            hostnameArg.setValue(myConnection.getHostName());
+          }
+          if (address == null) {
+            throw new CantRunException(DebuggerBundle.message("error.no.debug.attach.port"));
+          }
+          //noinspection HardCodedStringLiteral
+          final Connector.Argument portArg = myArguments.get("port");
+          if (portArg != null) {
+            portArg.setValue(address);
+          }
+        }
+        else {
+          if (address == null) {
+            throw new CantRunException(DebuggerBundle.message("error.no.shmem.address"));
+          }
+          //noinspection HardCodedStringLiteral
+          final Connector.Argument nameArg = myArguments.get("name");
+          if (nameArg != null) {
+            nameArg.setValue(address);
+          }
+        }
+        //noinspection HardCodedStringLiteral
+        final Connector.Argument timeoutArg = myArguments.get("timeout");
+        if (timeoutArg != null) {
+          timeoutArg.setValue("0"); // wait forever
+        }
+
+        myDebugProcessDispatcher.getMulticaster().connectorIsReady();
+        try {
+          if (SOCKET_ATTACHING_CONNECTOR_NAME.equals(connector.name()) && Patches.SUN_JDI_CONNECTOR_HANGUP_BUG) {
+            String portString = myConnection.getAddress();
+            String hostString = myConnection.getHostName();
+
+            if (hostString == null || hostString.isEmpty()) {
+              //noinspection HardCodedStringLiteral
+              hostString = "localhost";
+            }
+            hostString += ":";
+
+            final TransportServiceWrapper transportServiceWrapper = TransportServiceWrapper.getTransportService(connector.transport());
+            myConnectionService = transportServiceWrapper.attach(hostString + portString);
+            return myConnectionService.createVirtualMachine();
+          }
+          else {
+            return connector.attach(myArguments);
+          }
+        }
+        catch (IllegalArgumentException e) {
+          throw new CantRunException(e.getLocalizedMessage());
+        }
+      }
+    }
+    catch (IOException e) {
+      throw new ExecutionException(processError(e), e);
+    }
+    catch (IllegalConnectorArgumentsException e) {
+      throw new ExecutionException(processError(e), e);
+    }
+    finally {
+      myArguments = null;
+      myConnectionService = null;
+    }
+  }
+
+  public void showStatusText(final String text) {
+    if (!myStatusUpdateAlarm.isDisposed()) {
+      myStatusUpdateAlarm.cancelAllRequests();
+      myStatusUpdateAlarm.addRequest(new Runnable() {
+        public void run() {
+          final WindowManager wm = WindowManager.getInstance();
+          if (wm != null) {
+            wm.getStatusBar(myProject).setInfo(text);
+          }
+        }
+      }, 50);
+    }
+  }
+
+  static Connector findConnector(String connectorName) throws ExecutionException {
+    VirtualMachineManager virtualMachineManager;
+    try {
+      virtualMachineManager = Bootstrap.virtualMachineManager();
+    }
+    catch (Error e) {
+      final String error = e.getClass().getName() + " : " + e.getLocalizedMessage();
+      throw new ExecutionException(DebuggerBundle.message("debugger.jdi.bootstrap.error", error));
+    }
+    List connectors;
+    if (SOCKET_ATTACHING_CONNECTOR_NAME.equals(connectorName) || SHMEM_ATTACHING_CONNECTOR_NAME.equals(connectorName)) {
+      connectors = virtualMachineManager.attachingConnectors();
+    }
+    else if (SOCKET_LISTENING_CONNECTOR_NAME.equals(connectorName) || SHMEM_LISTENING_CONNECTOR_NAME.equals(connectorName)) {
+      connectors = virtualMachineManager.listeningConnectors();
+    }
+    else {
+      return null;
+    }
+    for (Object connector1 : connectors) {
+      Connector connector = (Connector)connector1;
+      if (connectorName.equals(connector.name())) {
+        return connector;
+      }
+    }
+    return null;
+  }
+
+  private void checkVirtualMachineVersion(VirtualMachine vm) {
+    final String version = vm.version();
+    if ("1.4.0".equals(version)) {
+      SwingUtilities.invokeLater(new Runnable() {
+        public void run() {
+          Messages.showMessageDialog(
+            getProject(),
+            DebuggerBundle.message("warning.jdk140.unstable"), DebuggerBundle.message("title.jdk140.unstable"), Messages.getWarningIcon()
+          );
+        }
+      });
+    }
+  }
+
+  /*Event dispatching*/
+  public void addEvaluationListener(EvaluationListener evaluationListener) {
+    myEvaluationDispatcher.addListener(evaluationListener);
+  }
+
+  public void removeEvaluationListener(EvaluationListener evaluationListener) {
+    myEvaluationDispatcher.removeListener(evaluationListener);
+  }
+
+  public void addDebugProcessListener(DebugProcessListener listener) {
+    myDebugProcessDispatcher.addListener(listener);
+  }
+
+  public void removeDebugProcessListener(DebugProcessListener listener) {
+    myDebugProcessDispatcher.removeListener(listener);
+  }
+
+  public void addProcessListener(ProcessListener processListener) {
+    synchronized(myProcessListeners) {
+      if(getExecutionResult() != null) {
+        getExecutionResult().getProcessHandler().addProcessListener(processListener);
+      }
+      else {
+        myProcessListeners.add(processListener);
+      }
+    }
+  }
+
+  public void removeProcessListener(ProcessListener processListener) {
+    synchronized (myProcessListeners) {
+      if(getExecutionResult() != null) {
+        getExecutionResult().getProcessHandler().removeProcessListener(processListener);
+      }
+      else {
+        myProcessListeners.remove(processListener);
+      }
+    }
+  }
+
+  /* getters */
+  public RemoteConnection getConnection() {
+    return myConnection;
+  }
+
+  public ExecutionResult getExecutionResult() {
+    return myExecutionResult;
+  }
+
+  public <T> T getUserData(Key<T> key) {
+    return (T)myUserData.get(key);
+  }
+
+  public <T> void putUserData(Key<T> key, T value) {
+    myUserData.put(key, value);
+  }
+
+  public Project getProject() {
+    return myProject;
+  }
+
+  public boolean canRedefineClasses() {
+    return myVirtualMachineProxy != null && myVirtualMachineProxy.canRedefineClasses();
+  }
+
+  public boolean canWatchFieldModification() {
+    return myVirtualMachineProxy != null && myVirtualMachineProxy.canWatchFieldModification();
+  }
+
+  public boolean isInInitialState() {
+    return myState.get() == STATE_INITIAL;
+  }
+
+  public boolean isAttached() {
+    return myState.get() == STATE_ATTACHED;
+  }
+
+  public boolean isDetached() {
+    return myState.get() == STATE_DETACHED;
+  }
+
+  public boolean isDetaching() {
+    return myState.get() == STATE_DETACHING;
+  }
+
+  public RequestManagerImpl getRequestsManager() {
+    return myRequestManager;
+  }
+
+  public VirtualMachineProxyImpl getVirtualMachineProxy() {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    if (myVirtualMachineProxy == null) {
+      throw new VMDisconnectedException();
+    }
+    return myVirtualMachineProxy;
+  }
+
+  public void appendPositionManager(final PositionManager positionManager) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    myPositionManager.appendPositionManager(positionManager);
+    DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager().updateBreakpoints(this);
+  }
+
+  private RunToCursorBreakpoint myRunToCursorBreakpoint;
+
+  public void cancelRunToCursorBreakpoint() {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    if (myRunToCursorBreakpoint != null) {
+      getRequestsManager().deleteRequest(myRunToCursorBreakpoint);
+      myRunToCursorBreakpoint.delete();
+      if (myRunToCursorBreakpoint.isRestoreBreakpoints()) {
+        final BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(getProject()).getBreakpointManager();
+        breakpointManager.enableBreakpoints(this);
+      }
+      myRunToCursorBreakpoint = null;
+    }
+  }
+
+  protected void closeProcess(boolean closedByUser) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+
+    if (myState.compareAndSet(STATE_INITIAL, STATE_DETACHING) || myState.compareAndSet(STATE_ATTACHED, STATE_DETACHING)) {
+      try {
+        getManagerThread().close();
+      }
+      finally {
+        myVirtualMachineProxy = null;
+        myPositionManager = null;
+        myReturnValueWatcher = null;
+        myNodeRederersMap.clear();
+        myRenderers.clear();
+        DebuggerUtils.cleanupAfterProcessFinish(this);
+        myState.set(STATE_DETACHED);
+        try {
+          myDebugProcessDispatcher.getMulticaster().processDetached(this, closedByUser);
+        }
+        finally {
+          setBreakpointsMuted(false);
+          myWaitFor.up();
+        }
+      }
+
+    }
+  }
+
+  private static String formatMessage(String message) {
+    final int lineLength = 90;
+    StringBuilder buf = new StringBuilder(message.length());
+    int index = 0;
+    while (index < message.length()) {
+      buf.append(message.substring(index, Math.min(index + lineLength, message.length()))).append('\n');
+      index += lineLength;
+    }
+    return buf.toString();
+  }
+
+  public static String processError(Exception e) {
+    String message;
+
+    if (e instanceof VMStartException) {
+      VMStartException e1 = (VMStartException)e;
+      message = e1.getLocalizedMessage();
+    }
+    else if (e instanceof IllegalConnectorArgumentsException) {
+      IllegalConnectorArgumentsException e1 = (IllegalConnectorArgumentsException)e;
+      final List<String> invalidArgumentNames = e1.argumentNames();
+      message = formatMessage(DebuggerBundle.message("error.invalid.argument", invalidArgumentNames.size()) + ": "+ e1.getLocalizedMessage()) + invalidArgumentNames;
+      if (LOG.isDebugEnabled()) {
+        LOG.debug(e1);
+      }
+    }
+    else if (e instanceof CantRunException) {
+      message = e.getLocalizedMessage();
+    }
+    else if (e instanceof VMDisconnectedException) {
+      message = DebuggerBundle.message("error.vm.disconnected");
+    }
+    else if (e instanceof UnknownHostException) {
+      message = DebuggerBundle.message("error.unknown.host") + ":\n" + e.getLocalizedMessage();
+    }
+    else if (e instanceof IOException) {
+      IOException e1 = (IOException)e;
+      final StringBuilder buf = StringBuilderSpinAllocator.alloc();
+      try {
+        buf.append(DebuggerBundle.message("error.cannot.open.debugger.port")).append(" : ");
+        buf.append(e1.getClass().getName()).append(" ");
+        final String localizedMessage = e1.getLocalizedMessage();
+        if (localizedMessage != null && !localizedMessage.isEmpty()) {
+          buf.append('"');
+          buf.append(localizedMessage);
+          buf.append('"');
+        }
+        if (LOG.isDebugEnabled()) {
+          LOG.debug(e1);
+        }
+        message = buf.toString();
+      }
+      finally {
+        StringBuilderSpinAllocator.dispose(buf);
+      }
+    }
+    else if (e instanceof ExecutionException) {
+      message = e.getLocalizedMessage();
+    }
+    else  {
+      message = DebuggerBundle.message("error.exception.while.connecting", e.getClass().getName(), e.getLocalizedMessage());
+      if (LOG.isDebugEnabled()) {
+        LOG.debug(e);
+      }
+    }
+    return message;
+  }
+
+  public void dispose() {
+    NodeRendererSettings.getInstance().removeListener(mySettingsListener);
+    Disposer.dispose(myDisposable);
+  }
+
+  public DebuggerManagerThreadImpl getManagerThread() {
+    if (myDebuggerManagerThread == null) {
+      synchronized (this) {
+        if (myDebuggerManagerThread == null) {
+          myDebuggerManagerThread = new DebuggerManagerThreadImpl(myDisposable);
+        }
+      }
+    }
+    return myDebuggerManagerThread;
+  }
+
+  private static int getInvokePolicy(SuspendContext suspendContext) {
+    //return ThreadReference.INVOKE_SINGLE_THREADED;
+    return suspendContext.getSuspendPolicy() == EventRequest.SUSPEND_EVENT_THREAD ? ObjectReference.INVOKE_SINGLE_THREADED : 0;
+  }
+
+  public void waitFor() {
+    LOG.assertTrue(!DebuggerManagerThreadImpl.isManagerThread());
+    myWaitFor.waitFor();
+  }
+
+  public void waitFor(long timeout) {
+    LOG.assertTrue(!DebuggerManagerThreadImpl.isManagerThread());
+    myWaitFor.waitFor(timeout);
+  }
+
+  private abstract class InvokeCommand <E extends Value> {
+    private final List myArgs;
+
+    protected InvokeCommand(List args) {
+      if (!args.isEmpty()) {
+        myArgs = new ArrayList(args);
+      }
+      else {
+        myArgs = args;
+      }
+    }
+
+    public String toString() {
+      return "INVOKE: " + super.toString();
+    }
+
+    protected abstract E invokeMethod(int invokePolicy, final List args) throws InvocationException,
+                                                                                ClassNotLoadedException,
+                                                                                IncompatibleThreadStateException,
+                                                                                InvalidTypeException;
+
+    public E start(EvaluationContextImpl evaluationContext, Method method) throws EvaluateException {
+      DebuggerManagerThreadImpl.assertIsManagerThread();
+      SuspendContextImpl suspendContext = evaluationContext.getSuspendContext();
+      SuspendManagerUtil.assertSuspendContext(suspendContext);
+
+      ThreadReferenceProxyImpl invokeThread = suspendContext.getThread();
+
+      if (SuspendManagerUtil.isEvaluating(getSuspendManager(), invokeThread)) {
+        throw EvaluateExceptionUtil.NESTED_EVALUATION_ERROR;
+      }
+
+      Set<SuspendContextImpl> suspendingContexts = SuspendManagerUtil.getSuspendingContexts(getSuspendManager(), invokeThread);
+      final ThreadReference invokeThreadRef = invokeThread.getThreadReference();
+
+      myEvaluationDispatcher.getMulticaster().evaluationStarted(suspendContext);
+      beforeMethodInvocation(suspendContext, method);
+
+      Object resumeData = null;
+      try {
+        for (final SuspendContextImpl suspendingContext : suspendingContexts) {
+          final ThreadReferenceProxyImpl suspendContextThread = suspendingContext.getThread();
+          if (suspendContextThread != invokeThread) {
+            if (LOG.isDebugEnabled()) {
+              LOG.debug("Resuming " + invokeThread + " that is paused by " + suspendContextThread);
+            }
+            LOG.assertTrue(suspendContextThread == null || !invokeThreadRef.equals(suspendContextThread.getThreadReference()));
+            getSuspendManager().resumeThread(suspendingContext, invokeThread);
+          }
+        }
+
+        resumeData = SuspendManagerUtil.prepareForResume(suspendContext);
+        suspendContext.setIsEvaluating(evaluationContext);
+
+        getVirtualMachineProxy().clearCaches();
+
+        while (true) {
+          try {
+            return invokeMethodAndFork(suspendContext);
+            }
+          catch (ClassNotLoadedException e) {
+            ReferenceType loadedClass;
+            try {
+              loadedClass = evaluationContext.isAutoLoadClasses()? loadClass(evaluationContext, e.className(), evaluationContext.getClassLoader()) : null;
+            }
+            catch (EvaluateException ignored) {
+              loadedClass = null;
+            }
+            if (loadedClass == null) {
+              throw EvaluateExceptionUtil.createEvaluateException(e);
+            }
+          }
+        }
+      }
+      catch (ClassNotLoadedException e) {
+        throw EvaluateExceptionUtil.createEvaluateException(e);
+      }
+      catch (InvocationException e) {
+        throw EvaluateExceptionUtil.createEvaluateException(e);
+      }
+      catch (IncompatibleThreadStateException e) {
+        throw EvaluateExceptionUtil.createEvaluateException(e);
+      }
+      catch (InvalidTypeException e) {
+        throw EvaluateExceptionUtil.createEvaluateException(e);
+      }
+      catch (ObjectCollectedException e) {
+        throw EvaluateExceptionUtil.createEvaluateException(e);
+      }
+      catch (UnsupportedOperationException e) {
+        throw EvaluateExceptionUtil.createEvaluateException(e);
+      }
+      catch (InternalException e) {
+        throw EvaluateExceptionUtil.createEvaluateException(e);
+      }
+      finally {
+        suspendContext.setIsEvaluating(null);
+        if (resumeData != null) {
+          SuspendManagerUtil.restoreAfterResume(suspendContext, resumeData);
+        }
+        for (SuspendContextImpl suspendingContext : mySuspendManager.getEventContexts()) {
+          if (suspendingContexts.contains(suspendingContext) && !suspendingContext.isEvaluating() && !suspendingContext.suspends(invokeThread)) {
+            mySuspendManager.suspendThread(suspendingContext, invokeThread);
+          }
+        }
+
+        if (LOG.isDebugEnabled()) {
+          LOG.debug("getVirtualMachine().clearCaches()");
+        }
+        getVirtualMachineProxy().clearCaches();
+        afterMethodInvocation(suspendContext);
+
+        myEvaluationDispatcher.getMulticaster().evaluationFinished(suspendContext);
+      }
+    }
+
+    private E invokeMethodAndFork(final SuspendContextImpl context) throws InvocationException,
+                                                                           ClassNotLoadedException,
+                                                                           IncompatibleThreadStateException,
+                                                                           InvalidTypeException {
+      final int invokePolicy = getInvokePolicy(context);
+      final Exception[] exception = new Exception[1];
+      final Value[] result = new Value[1];
+      getManagerThread().startLongProcessAndFork(new Runnable() {
+        public void run() {
+          ThreadReferenceProxyImpl thread = context.getThread();
+          try {
+            try {
+              if (LOG.isDebugEnabled()) {
+                final VirtualMachineProxyImpl virtualMachineProxy = getVirtualMachineProxy();
+                virtualMachineProxy.logThreads();
+                LOG.debug("Invoke in " + thread.name());
+                assertThreadSuspended(thread, context);
+              }
+              if (!Patches.IBM_JDK_DISABLE_COLLECTION_BUG) {
+                // ensure args are not collected
+                for (Object arg : myArgs) {
+                  if (arg instanceof ObjectReference) {
+                    ((ObjectReference)arg).disableCollection();
+                  }
+                }
+              }
+              result[0] = invokeMethod(invokePolicy, myArgs);
+            }
+            finally {
+              //  assertThreadSuspended(thread, context);
+              if (!Patches.IBM_JDK_DISABLE_COLLECTION_BUG) {
+                // ensure args are not collected
+                for (Object arg : myArgs) {
+                  if (arg instanceof ObjectReference) {
+                    ((ObjectReference)arg).enableCollection();
+                  }
+                }
+              }
+            }
+          }
+          catch (Exception e) {
+            exception[0] = e;
+          }
+        }
+      });
+
+      if (exception[0] != null) {
+        if (exception[0] instanceof InvocationException) {
+          throw (InvocationException)exception[0];
+        }
+        else if (exception[0] instanceof ClassNotLoadedException) {
+          throw (ClassNotLoadedException)exception[0];
+        }
+        else if (exception[0] instanceof IncompatibleThreadStateException) {
+          throw (IncompatibleThreadStateException)exception[0];
+        }
+        else if (exception[0] instanceof InvalidTypeException) {
+          throw (InvalidTypeException)exception[0];
+        }
+        else if (exception[0] instanceof RuntimeException) {
+          throw (RuntimeException)exception[0];
+        }
+        else {
+          LOG.assertTrue(false);
+        }
+      }
+
+      return (E)result[0];
+    }
+
+    private void assertThreadSuspended(final ThreadReferenceProxyImpl thread, final SuspendContextImpl context) {
+      LOG.assertTrue(context.isEvaluating());
+      try {
+        final boolean isSuspended = thread.isSuspended();
+        LOG.assertTrue(isSuspended, thread);
+      }
+      catch (ObjectCollectedException ignored) {
+      }
+    }
+  }
+
+  public Value invokeMethod(final EvaluationContext evaluationContext, final ObjectReference objRef, final Method method, final List args) throws EvaluateException {
+    return invokeInstanceMethod(evaluationContext, objRef, method, args, 0);
+  }
+
+  public Value invokeInstanceMethod(final EvaluationContext evaluationContext, final ObjectReference objRef, final Method method,
+                                     final List args, final int invocationOptions) throws EvaluateException {
+    final ThreadReference thread = getEvaluationThread(evaluationContext);
+    return new InvokeCommand<Value>(args) {
+      protected Value invokeMethod(int invokePolicy, final List args) throws InvocationException, ClassNotLoadedException, IncompatibleThreadStateException, InvalidTypeException {
+        if (LOG.isDebugEnabled()) {
+          LOG.debug("Invoke " + method.name());
+        }
+        return objRef.invokeMethod(thread, method, args, invokePolicy | invocationOptions);
+      }
+    }.start((EvaluationContextImpl)evaluationContext, method);
+  }
+
+  private static ThreadReference getEvaluationThread(final EvaluationContext evaluationContext) throws EvaluateException {
+    ThreadReferenceProxy evaluationThread = evaluationContext.getSuspendContext().getThread();
+    if(evaluationThread == null) {
+      throw EvaluateExceptionUtil.NULL_STACK_FRAME;
+    }
+    return evaluationThread.getThreadReference();
+  }
+
+  public Value invokeMethod(final EvaluationContext evaluationContext, final ClassType classType,
+                            final Method method,
+                            final List args) throws EvaluateException {
+
+    final ThreadReference thread = getEvaluationThread(evaluationContext);
+    InvokeCommand<Value> invokeCommand = new InvokeCommand<Value>(args) {
+      protected Value invokeMethod(int invokePolicy, final List args) throws InvocationException,
+                                                                             ClassNotLoadedException,
+                                                                             IncompatibleThreadStateException,
+                                                                             InvalidTypeException {
+        if (LOG.isDebugEnabled()) {
+          LOG.debug("Invoke " + method.name());
+        }
+        return classType.invokeMethod(thread, method, args, invokePolicy);
+      }
+    };
+    return invokeCommand.start((EvaluationContextImpl)evaluationContext, method);
+  }
+
+  public ArrayReference newInstance(final ArrayType arrayType,
+                                    final int dimension)
+    throws EvaluateException {
+    return arrayType.newInstance(dimension);
+  }
+
+  public ObjectReference newInstance(final EvaluationContext evaluationContext, final ClassType classType,
+                                     final Method method,
+                                     final List args) throws EvaluateException {
+    final ThreadReference thread = getEvaluationThread(evaluationContext);
+    InvokeCommand<ObjectReference> invokeCommand = new InvokeCommand<ObjectReference>(args) {
+      protected ObjectReference invokeMethod(int invokePolicy, final List args) throws InvocationException,
+                                                                                       ClassNotLoadedException,
+                                                                                       IncompatibleThreadStateException,
+                                                                                       InvalidTypeException {
+        if (LOG.isDebugEnabled()) {
+          LOG.debug("New instance " + method.name());
+        }
+        return classType.newInstance(thread, method, args, invokePolicy);
+      }
+    };
+    return invokeCommand.start((EvaluationContextImpl)evaluationContext, method);
+  }
+
+  public void clearCashes(int suspendPolicy) {
+    if (!isAttached()) return;
+    switch (suspendPolicy) {
+      case EventRequest.SUSPEND_ALL:
+        getVirtualMachineProxy().clearCaches();
+        break;
+      case EventRequest.SUSPEND_EVENT_THREAD:
+        getVirtualMachineProxy().clearCaches();
+        //suspendContext.getThread().clearAll();
+        break;
+    }
+  }
+
+  protected void beforeSuspend(SuspendContextImpl suspendContext) {
+    clearCashes(suspendContext.getSuspendPolicy());
+  }
+
+  private void beforeMethodInvocation(SuspendContextImpl suspendContext, Method method) {
+    if (LOG.isDebugEnabled()) {
+      LOG.debug(
+        "before invocation in  thread " + suspendContext.getThread().name() + " method " + (method == null ? "null" : method.name()));
+    }
+
+    if (method != null) {
+      showStatusText(DebuggerBundle.message("progress.evaluating", DebuggerUtilsEx.methodName(method)));
+    }
+    else {
+      showStatusText(DebuggerBundle.message("title.evaluating"));
+    }
+  }
+
+  private void afterMethodInvocation(SuspendContextImpl suspendContext) {
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("after invocation in  thread " + suspendContext.getThread().name());
+    }
+    showStatusText("");
+  }
+
+  public ReferenceType findClass(EvaluationContext evaluationContext, String className,
+                                 ClassLoaderReference classLoader) throws EvaluateException {
+    try {
+      DebuggerManagerThreadImpl.assertIsManagerThread();
+      final VirtualMachineProxyImpl vmProxy = getVirtualMachineProxy();
+      if (vmProxy == null) {
+        throw new VMDisconnectedException();
+      }
+      ReferenceType result = null;
+      for (final ReferenceType refType : vmProxy.classesByName(className)) {
+        if (refType.isPrepared() && isVisibleFromClassLoader(classLoader, refType)) {
+          result = refType;
+          break;
+        }
+      }
+      final EvaluationContextImpl evalContext = (EvaluationContextImpl)evaluationContext;
+      if (result == null && evalContext.isAutoLoadClasses()) {
+        return loadClass(evalContext, className, classLoader);
+      }
+      return result;
+    }
+    catch (InvocationException e) {
+      throw EvaluateExceptionUtil.createEvaluateException(e);
+    }
+    catch (ClassNotLoadedException e) {
+      throw EvaluateExceptionUtil.createEvaluateException(e);
+    }
+    catch (IncompatibleThreadStateException e) {
+      throw EvaluateExceptionUtil.createEvaluateException(e);
+    }
+    catch (InvalidTypeException e) {
+      throw EvaluateExceptionUtil.createEvaluateException(e);
+    }
+  }
+
+  private static boolean isVisibleFromClassLoader(final ClassLoaderReference fromLoader, final ReferenceType refType) {
+    // IMPORTANT! Even if the refType is already loaded by some parent or bootstrap loader, it may not be visible from the given loader.
+    // For example because there were no accesses yet from this loader to this class. So the loader is not in the list of "initialing" loaders
+    // for this refType and the refType is not visible to the loader.
+    // Attempt to evaluate method with this refType will yield ClassNotLoadedException.
+    // The only way to say for sure whether the class is _visible_ to the given loader, is to use the following API call
+    return fromLoader == null || fromLoader.visibleClasses().contains(refType);
+  }
+
+  private static String reformatArrayName(String className) {
+    if (className.indexOf('[') == -1) return className;
+
+    int dims = 0;
+    while (className.endsWith("[]")) {
+      className = className.substring(0, className.length() - 2);
+      dims++;
+    }
+
+    StringBuilder buffer = StringBuilderSpinAllocator.alloc();
+    try {
+      for (int i = 0; i < dims; i++) {
+        buffer.append('[');
+      }
+      String primitiveSignature = JVMNameUtil.getPrimitiveSignature(className);
+      if(primitiveSignature != null) {
+        buffer.append(primitiveSignature);
+      }
+      else {
+        buffer.append('L');
+        buffer.append(className);
+        buffer.append(';');
+      }
+      return buffer.toString();
+    }
+    finally {
+      StringBuilderSpinAllocator.dispose(buffer);
+    }
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  public ReferenceType loadClass(EvaluationContextImpl evaluationContext, String qName, ClassLoaderReference classLoader)
+    throws InvocationException, ClassNotLoadedException, IncompatibleThreadStateException, InvalidTypeException, EvaluateException {
+
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    qName = reformatArrayName(qName);
+    ReferenceType refType = null;
+    VirtualMachineProxyImpl virtualMachine = getVirtualMachineProxy();
+    final List classClasses = virtualMachine.classesByName("java.lang.Class");
+    if (!classClasses.isEmpty()) {
+      ClassType classClassType = (ClassType)classClasses.get(0);
+      final Method forNameMethod;
+      if (classLoader != null) {
+        //forNameMethod = classClassType.concreteMethodByName("forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;");
+        forNameMethod = DebuggerUtils.findMethod(classClassType, "forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;");
+      }
+      else {
+        //forNameMethod = classClassType.concreteMethodByName("forName", "(Ljava/lang/String;)Ljava/lang/Class;");
+        forNameMethod = DebuggerUtils.findMethod(classClassType, "forName", "(Ljava/lang/String;)Ljava/lang/Class;");
+      }
+      final List<Mirror> args = new ArrayList<Mirror>(); // do not use unmodifiable lists because the list is modified by JPDA
+      final StringReference qNameMirror = virtualMachine.mirrorOf(qName);
+      args.add(qNameMirror);
+      if (classLoader != null) {
+        args.add(virtualMachine.mirrorOf(true));
+        args.add(classLoader);
+      }
+      final Value value = invokeMethod(evaluationContext, classClassType, forNameMethod, args);
+      if (value instanceof ClassObjectReference) {
+        refType = ((ClassObjectReference)value).reflectedType();
+      }
+    }
+    return refType;
+  }
+
+  public void logThreads() {
+    if (LOG.isDebugEnabled()) {
+      try {
+        Collection<ThreadReferenceProxyImpl> allThreads = getVirtualMachineProxy().allThreads();
+        for (ThreadReferenceProxyImpl threadReferenceProxy : allThreads) {
+          LOG.debug("Thread name=" + threadReferenceProxy.name() + " suspendCount()=" + threadReferenceProxy.getSuspendCount());
+        }
+      }
+      catch (Exception e) {
+        LOG.debug(e);
+      }
+    }
+  }
+
+  public SuspendManager getSuspendManager() {
+    return mySuspendManager;
+  }
+
+  public CompoundPositionManager getPositionManager() {
+    return myPositionManager;
+  }
+  //ManagerCommands
+
+  public void stop(boolean forceTerminate) {
+    this.getManagerThread().terminateAndInvoke(createStopCommand(forceTerminate), DebuggerManagerThreadImpl.COMMAND_TIMEOUT);
+  }
+
+  public StopCommand createStopCommand(boolean forceTerminate) {
+    return new StopCommand(forceTerminate);
+  }
+
+  protected class StopCommand extends DebuggerCommandImpl {
+    private final boolean myIsTerminateTargetVM;
+
+    public StopCommand(boolean isTerminateTargetVM) {
+      myIsTerminateTargetVM = isTerminateTargetVM;
+    }
+
+    public Priority getPriority() {
+      return Priority.HIGH;
+    }
+
+    protected void action() throws Exception {
+      if (isAttached()) {
+        final VirtualMachineProxyImpl virtualMachineProxy = getVirtualMachineProxy();
+        if (myIsTerminateTargetVM) {
+          virtualMachineProxy.exit(-1);
+        }
+        else {
+          // some VM's (like IBM VM 1.4.2 bundled with WebSpere) does not
+          // resume threads on dispose() like it should
+          virtualMachineProxy.resume();
+          virtualMachineProxy.dispose();
+        }
+      }
+      else {
+        stopConnecting();
+      }
+    }
+  }
+
+  private class StepOutCommand extends ResumeCommand {
+    public StepOutCommand(SuspendContextImpl suspendContext) {
+      super(suspendContext);
+    }
+
+    public void contextAction() {
+      showStatusText(DebuggerBundle.message("status.step.out"));
+      final SuspendContextImpl suspendContext = getSuspendContext();
+      final ThreadReferenceProxyImpl thread = getContextThread();
+      RequestHint hint = new RequestHint(thread, suspendContext, StepRequest.STEP_OUT);
+      hint.setIgnoreFilters(mySession.shouldIgnoreSteppingFilters());
+      applyThreadFilter(thread);
+      final MethodReturnValueWatcher rvWatcher = myReturnValueWatcher;
+      if (rvWatcher != null) {
+        rvWatcher.enable(thread.getThreadReference());
+      }
+      doStep(suspendContext, thread, StepRequest.STEP_OUT, hint);
+      super.contextAction();
+    }
+  }
+
+  private class StepIntoCommand extends ResumeCommand {
+    private final boolean myForcedIgnoreFilters;
+    private final RequestHint.SmartStepFilter mySmartStepFilter;
+
+    public StepIntoCommand(SuspendContextImpl suspendContext, boolean ignoreFilters, @Nullable final RequestHint.SmartStepFilter smartStepFilter) {
+      super(suspendContext);
+      myForcedIgnoreFilters = ignoreFilters || smartStepFilter != null;
+      mySmartStepFilter = smartStepFilter;
+    }
+
+    public void contextAction() {
+      showStatusText(DebuggerBundle.message("status.step.into"));
+      final SuspendContextImpl suspendContext = getSuspendContext();
+      final ThreadReferenceProxyImpl stepThread = getContextThread();
+      final RequestHint hint = mySmartStepFilter != null?
+                               new RequestHint(stepThread, suspendContext, mySmartStepFilter) :
+                               new RequestHint(stepThread, suspendContext, StepRequest.STEP_INTO);
+      if (myForcedIgnoreFilters) {
+        try {
+          mySession.setIgnoreStepFiltersFlag(stepThread.frameCount());
+        }
+        catch (EvaluateException e) {
+          LOG.info(e);
+        }
+      }
+      hint.setIgnoreFilters(myForcedIgnoreFilters || mySession.shouldIgnoreSteppingFilters());
+      applyThreadFilter(stepThread);
+      doStep(suspendContext, stepThread, StepRequest.STEP_INTO, hint);
+      super.contextAction();
+    }
+  }
+
+  private class StepOverCommand extends ResumeCommand {
+    private final boolean myIsIgnoreBreakpoints;
+
+    public StepOverCommand(SuspendContextImpl suspendContext, boolean ignoreBreakpoints) {
+      super(suspendContext);
+      myIsIgnoreBreakpoints = ignoreBreakpoints;
+    }
+
+    public void contextAction() {
+      showStatusText(DebuggerBundle.message("status.step.over"));
+      final SuspendContextImpl suspendContext = getSuspendContext();
+      final ThreadReferenceProxyImpl stepThread = getContextThread();
+      // need this hint whil stepping over for JSR45 support:
+      // several lines of generated java code may correspond to a single line in the source file,
+      // from which the java code was generated
+      RequestHint hint = new RequestHint(stepThread, suspendContext, StepRequest.STEP_OVER);
+      hint.setRestoreBreakpoints(myIsIgnoreBreakpoints);
+      hint.setIgnoreFilters(myIsIgnoreBreakpoints || mySession.shouldIgnoreSteppingFilters());
+
+      applyThreadFilter(stepThread);
+
+      final MethodReturnValueWatcher rvWatcher = myReturnValueWatcher;
+      if (rvWatcher != null) {
+        rvWatcher.enable(stepThread.getThreadReference());
+      }
+
+      doStep(suspendContext, stepThread, StepRequest.STEP_OVER, hint);
+
+      if (myIsIgnoreBreakpoints) {
+        DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager().disableBreakpoints(DebugProcessImpl.this);
+      }
+      super.contextAction();
+    }
+  }
+
+  private class RunToCursorCommand extends ResumeCommand {
+    private final RunToCursorBreakpoint myRunToCursorBreakpoint;
+    private final boolean myIgnoreBreakpoints;
+
+    private RunToCursorCommand(SuspendContextImpl suspendContext, Document document, int lineIndex, final boolean ignoreBreakpoints) {
+      super(suspendContext);
+      myIgnoreBreakpoints = ignoreBreakpoints;
+      final BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager();
+      myRunToCursorBreakpoint = breakpointManager.addRunToCursorBreakpoint(document, lineIndex, ignoreBreakpoints);
+    }
+
+    public void contextAction() {
+      showStatusText(DebuggerBundle.message("status.run.to.cursor"));
+      cancelRunToCursorBreakpoint();
+      if (myRunToCursorBreakpoint == null) {
+        return;
+      }
+      if (myIgnoreBreakpoints) {
+        final BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager();
+        breakpointManager.disableBreakpoints(DebugProcessImpl.this);
+      }
+      applyThreadFilter(getContextThread());
+      final SuspendContextImpl context = getSuspendContext();
+      myRunToCursorBreakpoint.SUSPEND_POLICY = context.getSuspendPolicy() == EventRequest.SUSPEND_EVENT_THREAD? DebuggerSettings.SUSPEND_THREAD : DebuggerSettings.SUSPEND_ALL;
+      myRunToCursorBreakpoint.LOG_ENABLED = false;
+      myRunToCursorBreakpoint.createRequest(context.getDebugProcess());
+      DebugProcessImpl.this.myRunToCursorBreakpoint = myRunToCursorBreakpoint;
+      super.contextAction();
+    }
+  }
+
+  public abstract class ResumeCommand extends SuspendContextCommandImpl {
+
+    private final ThreadReferenceProxyImpl myContextThread;
+
+    public ResumeCommand(SuspendContextImpl suspendContext) {
+      super(suspendContext);
+      final ThreadReferenceProxyImpl contextThread = mySession.getContextManager().getContext().getThreadProxy();
+      myContextThread = contextThread != null ? contextThread : getSuspendContext().getThread();
+    }
+
+    public Priority getPriority() {
+      return Priority.HIGH;
+    }
+
+    public void contextAction() {
+      showStatusText(DebuggerBundle.message("status.process.resumed"));
+      getSuspendManager().resume(getSuspendContext());
+      myDebugProcessDispatcher.getMulticaster().resumed(getSuspendContext());
+    }
+
+    public ThreadReferenceProxyImpl getContextThread() {
+      return myContextThread;
+    }
+
+    protected void applyThreadFilter(ThreadReferenceProxy thread) {
+      if (getSuspendContext().getSuspendPolicy() == EventRequest.SUSPEND_ALL) {
+        // there could be explicit resume as a result of call to voteSuspend()
+        // e.g. when breakpoint was considered invalid, in that case the filter will be applied _after_
+        // resuming and all breakpoints in other threads will be ignored.
+        // As resume() implicitly cleares the filter, the filter must be always applied _before_ any resume() action happens
+        final BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(getProject()).getBreakpointManager();
+        breakpointManager.applyThreadFilter(DebugProcessImpl.this, thread.getThreadReference());
+      }
+    }
+  }
+
+  private class PauseCommand extends DebuggerCommandImpl {
+    public PauseCommand() {
+    }
+
+    public void action() {
+      if (!isAttached() || getVirtualMachineProxy().isPausePressed()) {
+        return;
+      }
+      logThreads();
+      getVirtualMachineProxy().suspend();
+      logThreads();
+      SuspendContextImpl suspendContext = mySuspendManager.pushSuspendContext(EventRequest.SUSPEND_ALL, 0);
+      myDebugProcessDispatcher.getMulticaster().paused(suspendContext);
+    }
+  }
+
+  private class ResumeThreadCommand extends SuspendContextCommandImpl {
+    private final ThreadReferenceProxyImpl myThread;
+
+    public ResumeThreadCommand(SuspendContextImpl suspendContext, ThreadReferenceProxyImpl thread) {
+      super(suspendContext);
+      myThread = thread;
+    }
+
+    public void contextAction() {
+      if (getSuspendManager().isFrozen(myThread)) {
+        getSuspendManager().unfreezeThread(myThread);
+        return;
+      }
+
+      final Set<SuspendContextImpl> suspendingContexts = SuspendManagerUtil.getSuspendingContexts(getSuspendManager(), myThread);
+      for (SuspendContextImpl suspendContext : suspendingContexts) {
+        if (suspendContext.getThread() == myThread) {
+          DebugProcessImpl.this.getManagerThread().invoke(createResumeCommand(suspendContext));
+        }
+        else {
+          getSuspendManager().resumeThread(suspendContext, myThread);
+        }
+      }
+    }
+  }
+
+  private class FreezeThreadCommand extends DebuggerCommandImpl {
+    private final ThreadReferenceProxyImpl myThread;
+
+    public FreezeThreadCommand(ThreadReferenceProxyImpl thread) {
+      myThread = thread;
+    }
+
+    protected void action() throws Exception {
+      SuspendManager suspendManager = getSuspendManager();
+      if (!suspendManager.isFrozen(myThread)) {
+        suspendManager.freezeThread(myThread);
+      }
+    }
+  }
+
+  private class PopFrameCommand extends SuspendContextCommandImpl {
+    private final StackFrameProxyImpl myStackFrame;
+
+    public PopFrameCommand(SuspendContextImpl context, StackFrameProxyImpl frameProxy) {
+      super(context);
+      myStackFrame = frameProxy;
+    }
+
+    public void contextAction() {
+      final ThreadReferenceProxyImpl thread = myStackFrame.threadProxy();
+      try {
+        if (!getSuspendManager().isSuspended(thread)) {
+          notifyCancelled();
+          return;
+        }
+      }
+      catch (ObjectCollectedException e) {
+        notifyCancelled();
+        return;
+      }
+
+      final SuspendContextImpl suspendContext = getSuspendContext();
+      if (!suspendContext.suspends(thread)) {
+        suspendContext.postponeCommand(this);
+        return;
+      }
+
+      if (myStackFrame.isBottom()) {
+        DebuggerInvocationUtil.swingInvokeLater(myProject, new Runnable() {
+          public void run() {
+            Messages.showMessageDialog(myProject, DebuggerBundle.message("error.pop.bottom.stackframe"), ActionsBundle.actionText(DebuggerActions.POP_FRAME), Messages.getErrorIcon());
+          }
+        });
+        return;
+      }
+
+      try {
+        thread.popFrames(myStackFrame);
+      }
+      catch (final EvaluateException e) {
+        DebuggerInvocationUtil.swingInvokeLater(myProject, new Runnable() {
+          public void run() {
+            Messages.showMessageDialog(myProject, DebuggerBundle.message("error.pop.stackframe", e.getLocalizedMessage()), ActionsBundle.actionText(DebuggerActions.POP_FRAME), Messages.getErrorIcon());
+          }
+        });
+        LOG.info(e);
+      }
+      finally {
+        getSuspendManager().popFrame(suspendContext);
+      }
+    }
+  }
+
+  @NotNull
+  public GlobalSearchScope getSearchScope() {
+    LOG.assertTrue(mySession != null, "Accessing debug session before its initialization");
+    return mySession.getSearchScope();
+  }
+
+  @Nullable
+  public ExecutionResult attachVirtualMachine(final Executor executor,
+                                              final ProgramRunner runner,
+                                              final DebuggerSession session,
+                                              final RunProfileState state,
+                                              final RemoteConnection remoteConnection,
+                                              boolean pollConnection) throws ExecutionException {
+    return attachVirtualMachine(new DefaultDebugEnvironment(myProject,
+                                                        executor,
+                                                        runner,
+                                                        state.getRunnerSettings().getRunProfile(),
+                                                        state,
+                                                        remoteConnection,
+                                                        pollConnection),
+                                session);
+  }
+
+  @Nullable
+  public ExecutionResult attachVirtualMachine(final DebugEnvironment environment,
+                                              final DebuggerSession session) throws ExecutionException {
+    mySession = session;
+    myWaitFor.down();
+
+    ApplicationManager.getApplication().assertIsDispatchThread();
+    LOG.assertTrue(isInInitialState());
+
+    myConnection = environment.getRemoteConnection();
+
+    createVirtualMachine(environment.getSessionName(), environment.isPollConnection());
+
+    try {
+      synchronized (myProcessListeners) {
+        myExecutionResult = environment.createExecutionResult();
+        if (myExecutionResult == null) {
+          fail();
+          return null;
+        }
+        for (ProcessListener processListener : myProcessListeners) {
+          myExecutionResult.getProcessHandler().addProcessListener(processListener);
+        }
+        myProcessListeners.clear();
+      }
+    }
+    catch (ExecutionException e) {
+      fail();
+      throw e;
+    }
+
+    // writing to volatile field ensures the other threads will see the right values in non-volatile fields
+    myDebugProcessStarted = true;
+
+    if (ApplicationManager.getApplication().isUnitTestMode()) {
+      return myExecutionResult;
+    }
+
+    /*
+    final Alarm debugPortTimeout = new Alarm(Alarm.ThreadToUse.SHARED_THREAD);
+
+    myExecutionResult.getProcessHandler().addProcessListener(new ProcessAdapter() {
+      public void processTerminated(ProcessEvent event) {
+        debugPortTimeout.cancelAllRequests();
+      }
+
+      public void startNotified(ProcessEvent event) {
+        debugPortTimeout.addRequest(new Runnable() {
+          public void run() {
+            if(isInInitialState()) {
+              ApplicationManager.getApplication().schedule(new Runnable() {
+                public void run() {
+                  String message = DebuggerBundle.message("status.connect.failed", DebuggerBundle.getAddressDisplayName(remoteConnection), DebuggerBundle.getTransportName(remoteConnection));
+                  Messages.showErrorDialog(myProject, message, DebuggerBundle.message("title.generic.debug.dialog"));
+                }
+              });
+            }
+          }
+        }, LOCAL_START_TIMEOUT);
+      }
+    });
+    */
+
+    return myExecutionResult;
+  }
+
+  private void fail() {
+    synchronized (this) {
+      if (myIsFailed) {
+        // need this in order to prevent calling stop() twice
+        return;
+      }
+      myIsFailed = true;
+    }
+    stop(false);
+  }
+
+  private void createVirtualMachine(final String sessionName, final boolean pollConnection) {
+    final Semaphore semaphore = new Semaphore();
+    semaphore.down();
+
+    final Ref<Boolean> connectorIsReady = Ref.create(false);
+    myDebugProcessDispatcher.addListener(new DebugProcessAdapter() {
+      public void connectorIsReady() {
+        connectorIsReady.set(true);
+        semaphore.up();
+        myDebugProcessDispatcher.removeListener(this);
+      }
+    });
+
+
+    this.getManagerThread().schedule(new DebuggerCommandImpl() {
+      protected void action() {
+        VirtualMachine vm = null;
+
+        try {
+          final long time = System.currentTimeMillis();
+          while (System.currentTimeMillis() - time < LOCAL_START_TIMEOUT) {
+            try {
+              vm = createVirtualMachineInt();
+              break;
+            }
+            catch (final ExecutionException e) {
+              if (pollConnection && !myConnection.isServerMode() && e.getCause() instanceof IOException) {
+                synchronized (this) {
+                  try {
+                    wait(500);
+                  }
+                  catch (InterruptedException ie) {
+                    break;
+                  }
+                }
+              }
+              else {
+                fail();
+                if (myExecutionResult != null || !connectorIsReady.get()) {
+                  // propagate exception only in case we succeded to obtain execution result,
+                  // otherwise if the error is induced by the fact that there is nothing to debug, and there is no need to show
+                  // this problem to the user
+                  SwingUtilities.invokeLater(new Runnable() {
+                    public void run() {
+                      ExecutionUtil.handleExecutionError(myProject, ToolWindowId.DEBUG, sessionName, e);
+                    }
+                  });
+                }
+                break;
+              }
+            }
+          }
+        }
+        finally {
+          semaphore.up();
+        }
+
+        if (vm != null) {
+          final VirtualMachine vm1 = vm;
+          afterProcessStarted(new Runnable() {
+            public void run() {
+              getManagerThread().schedule(new DebuggerCommandImpl() {
+                protected void action() throws Exception {
+                  commitVM(vm1);
+                }
+              });
+            }
+          });
+        }
+      }
+
+      protected void commandCancelled() {
+        try {
+          super.commandCancelled();
+        }
+        finally {
+          semaphore.up();
+        }
+      }
+    });
+
+    semaphore.waitFor();
+  }
+
+  private void afterProcessStarted(final Runnable run) {
+    class MyProcessAdapter extends ProcessAdapter {
+      private boolean alreadyRun = false;
+
+      public synchronized void run() {
+        if(!alreadyRun) {
+          alreadyRun = true;
+          run.run();
+        }
+        removeProcessListener(this);
+      }
+
+      public void startNotified(ProcessEvent event) {
+        run();
+      }
+    }
+    MyProcessAdapter processListener = new MyProcessAdapter();
+    addProcessListener(processListener);
+    if(myExecutionResult != null) {
+      if(myExecutionResult.getProcessHandler().isStartNotified()) {
+        processListener.run();
+      }
+    }
+  }
+
+  public boolean isPausePressed() {
+    return myVirtualMachineProxy != null && myVirtualMachineProxy.isPausePressed();
+  }
+
+  public DebuggerCommandImpl createPauseCommand() {
+    return new PauseCommand();
+  }
+
+  public ResumeCommand createResumeCommand(SuspendContextImpl suspendContext) {
+    return createResumeCommand(suspendContext, PrioritizedTask.Priority.HIGH);
+  }
+
+  public ResumeCommand createResumeCommand(SuspendContextImpl suspendContext, final PrioritizedTask.Priority priority) {
+    final BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(getProject()).getBreakpointManager();
+    return new ResumeCommand(suspendContext) {
+      public void contextAction() {
+        breakpointManager.applyThreadFilter(DebugProcessImpl.this, null); // clear the filter on resume
+        super.contextAction();
+      }
+
+      public Priority getPriority() {
+        return priority;
+      }
+    };
+  }
+
+  public ResumeCommand createStepOverCommand(SuspendContextImpl suspendContext, boolean ignoreBreakpoints) {
+    return new StepOverCommand(suspendContext, ignoreBreakpoints);
+  }
+
+  public ResumeCommand createStepOutCommand(SuspendContextImpl suspendContext) {
+    return new StepOutCommand(suspendContext);
+  }
+
+  public ResumeCommand createStepIntoCommand(SuspendContextImpl suspendContext, boolean ignoreFilters, final RequestHint.SmartStepFilter smartStepFilter) {
+    return new StepIntoCommand(suspendContext, ignoreFilters, smartStepFilter);
+  }
+
+  public ResumeCommand createRunToCursorCommand(SuspendContextImpl suspendContext, Document document, int lineIndex,
+                                                            final boolean ignoreBreakpoints)
+    throws EvaluateException {
+    RunToCursorCommand runToCursorCommand = new RunToCursorCommand(suspendContext, document, lineIndex, ignoreBreakpoints);
+    if(runToCursorCommand.myRunToCursorBreakpoint == null) {
+      final PsiFile psiFile = PsiDocumentManager.getInstance(getProject()).getPsiFile(document);
+      throw new EvaluateException(DebuggerBundle.message("error.running.to.cursor.no.executable.code", psiFile != null? psiFile.getName() : "<No File>", lineIndex), null);
+    }
+    return runToCursorCommand;
+  }
+
+  public DebuggerCommandImpl createFreezeThreadCommand(ThreadReferenceProxyImpl thread) {
+    return new FreezeThreadCommand(thread);
+  }
+
+  public SuspendContextCommandImpl createResumeThreadCommand(SuspendContextImpl suspendContext, ThreadReferenceProxyImpl thread) {
+    return new ResumeThreadCommand(suspendContext, thread);
+  }
+
+  public SuspendContextCommandImpl createPopFrameCommand(DebuggerContextImpl context, StackFrameProxyImpl stackFrame) {
+    final SuspendContextImpl contextByThread =
+      SuspendManagerUtil.findContextByThread(context.getDebugProcess().getSuspendManager(), stackFrame.threadProxy());
+    return new PopFrameCommand(contextByThread, stackFrame);
+  }
+
+  public void setBreakpointsMuted(final boolean muted) {
+    if (isAttached()) {
+      getManagerThread().schedule(new DebuggerCommandImpl() {
+        protected void action() throws Exception {
+          // set the flag before enabling/disabling cause it affects if breakpoints will create requests
+          if (myBreakpointsMuted.getAndSet(muted) != muted) {
+            final BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager();
+            if (muted) {
+              breakpointManager.disableBreakpoints(DebugProcessImpl.this);
+            }
+            else {
+              breakpointManager.enableBreakpoints(DebugProcessImpl.this);
+            }
+          }
+        }
+      });
+    }
+    else {
+      myBreakpointsMuted.set(muted);
+    }
+  }
+
+
+  public boolean areBreakpointsMuted() {
+    return myBreakpointsMuted.get();
+  }
+}
+
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/DebuggerManagerThreadImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/DebuggerManagerThreadImpl.java
new file mode 100644
index 0000000..df7a6d3
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/DebuggerManagerThreadImpl.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine;
+
+import com.intellij.debugger.engine.events.DebuggerCommandImpl;
+import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
+import com.intellij.debugger.engine.managerThread.DebuggerCommand;
+import com.intellij.debugger.engine.managerThread.DebuggerManagerThread;
+import com.intellij.debugger.engine.managerThread.SuspendContextCommand;
+import com.intellij.debugger.impl.InvokeAndWaitThread;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.progress.ProgressManager;
+import com.intellij.openapi.progress.util.ProgressIndicatorListenerAdapter;
+import com.intellij.openapi.progress.util.ProgressWindowWithNotification;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.util.Alarm;
+import com.sun.jdi.VMDisconnectedException;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.TestOnly;
+
+/**
+ * @author lex
+ */
+public class DebuggerManagerThreadImpl extends InvokeAndWaitThread<DebuggerCommandImpl> implements DebuggerManagerThread, Disposable {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.DebuggerManagerThreadImpl");
+  public static final int COMMAND_TIMEOUT = 3000;
+  private static final int RESTART_TIMEOUT = 500;
+  private volatile boolean myDisposed;
+
+  DebuggerManagerThreadImpl(@NotNull Disposable parent) {
+    Disposer.register(parent, this);
+  }
+
+  public void dispose() {
+    myDisposed = true;
+  }
+
+  @TestOnly
+  public static DebuggerManagerThreadImpl createTestInstance(@NotNull Disposable parent) {
+    return new DebuggerManagerThreadImpl(parent);
+  }
+
+  public static boolean isManagerThread() {
+    return currentThread() instanceof DebuggerManagerThreadImpl;
+  }
+
+  public static void assertIsManagerThread() {
+    LOG.assertTrue(isManagerThread(), "Should be invoked in manager thread, use DebuggerManagerThreadImpl.getInstance(..).invoke...");
+  }
+
+  public void invokeAndWait(DebuggerCommandImpl managerCommand) {
+    LOG.assertTrue(!ApplicationManager.getApplication().isDispatchThread());
+    LOG.assertTrue(!(currentThread() instanceof DebuggerManagerThreadImpl),
+                   "Should be invoked outside manager thread, use DebuggerManagerThreadImpl.getInstance(..).invoke...");
+    super.invokeAndWait(managerCommand);
+  }
+
+  public void invoke(DebuggerCommandImpl managerCommand) {
+    if (currentThread() instanceof DebuggerManagerThreadImpl) {
+      processEvent(managerCommand);
+    }
+    else {
+      schedule(managerCommand);
+    }
+  }
+
+  public boolean pushBack(DebuggerCommandImpl managerCommand) {
+    final boolean pushed = super.pushBack(managerCommand);
+    if (!pushed) {
+      managerCommand.notifyCancelled();
+    }
+    return pushed;
+  }
+
+  public boolean schedule(DebuggerCommandImpl managerCommand) {
+    final boolean scheduled = super.schedule(managerCommand);
+    if (!scheduled) {
+      managerCommand.notifyCancelled();
+    }
+    return scheduled;
+  }
+
+  /**
+   * waits COMMAND_TIMEOUT milliseconds
+   * if worker thread is still processing the same command
+   * calls terminateCommand
+   */
+  public void terminateAndInvoke(DebuggerCommandImpl command, int terminateTimeout) {
+    final DebuggerCommandImpl currentCommand = myEvents.getCurrentEvent();
+
+    invoke(command);
+
+    if (currentCommand != null) {
+      final Alarm alarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD);
+      alarm.addRequest(new Runnable() {
+        public void run() {
+          try {
+            if (currentCommand == myEvents.getCurrentEvent()) {
+              // if current command is still in progress, cancel it
+              getCurrentRequest().interrupt();
+              try {
+                getCurrentRequest().join();
+              }
+              catch (InterruptedException ignored) {
+              }
+              catch (Exception e) {
+                throw new RuntimeException(e);
+              }
+              finally {
+                if (!myDisposed) {
+                  startNewWorkerThread();
+                }
+              }
+            }
+          }
+          finally {
+            Disposer.dispose(alarm);
+          }
+        }
+      }, terminateTimeout);
+    }
+  }
+
+
+  public void processEvent(@NotNull DebuggerCommandImpl managerCommand) {
+    assertIsManagerThread();
+    try {
+      if(myEvents.isClosed()) {
+        managerCommand.notifyCancelled();
+      }
+      else {
+        managerCommand.run();
+      }
+    }
+    catch (VMDisconnectedException e) {
+      LOG.debug(e);
+    }
+    catch (RuntimeException e) {
+      throw e;
+    }
+    catch (InterruptedException e) {
+      throw new RuntimeException(e);
+    }
+    catch (Exception e) {
+      LOG.error(e);
+    }
+  }
+
+  public void startProgress(final DebuggerCommandImpl command, final ProgressWindowWithNotification progressWindow) {
+    progressWindow.addListener(new ProgressIndicatorListenerAdapter() {
+      public void cancelled() {
+        command.release();
+      }
+    });
+
+    ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
+      public void run() {
+        ProgressManager.getInstance().runProcess(new Runnable() {
+          public void run() {
+            invokeAndWait(command);
+          }
+        }, progressWindow);
+      }
+    });
+  }
+
+
+  public void startLongProcessAndFork(Runnable process) {
+    startNewWorkerThread();
+
+    try {
+      process.run();
+    }
+    finally {
+      final WorkerThreadRequest request = getCurrentThreadRequest();
+
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("Switching back to " + request);
+      }
+
+      super.invokeAndWait(new DebuggerCommandImpl() {
+        protected void action() throws Exception {
+          switchToRequest(request);
+        }
+
+        protected void commandCancelled() {
+          if (LOG.isDebugEnabled()) {
+            LOG.debug("Event queue was closed, killing request");
+          }
+          request.interrupt();
+        }
+      });
+    }
+  }
+
+  public void invokeCommand(final DebuggerCommand command) {
+    if(command instanceof SuspendContextCommand) {
+      SuspendContextCommand suspendContextCommand = (SuspendContextCommand)command;
+      schedule(new SuspendContextCommandImpl((SuspendContextImpl)suspendContextCommand.getSuspendContext()) {
+          public void contextAction() throws Exception {
+            command.action();
+          }
+
+          protected void commandCancelled() {
+            command.commandCancelled();
+          }
+        });
+    }
+    else {
+      schedule(new DebuggerCommandImpl() {
+        protected void action() throws Exception {
+          command.action();
+        }
+
+        protected void commandCancelled() {
+          command.commandCancelled();
+        }
+      });
+    }
+
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JVMName.java b/java/debugger/impl/src/com/intellij/debugger/engine/JVMName.java
new file mode 100644
index 0000000..9d47e31
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/JVMName.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine;
+
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+
+/**
+ * @author lex
+ */
+public interface JVMName {
+  String getName(DebugProcessImpl process) throws EvaluateException;
+
+  String getDisplayName(DebugProcessImpl debugProcess);
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JVMNameUtil.java b/java/debugger/impl/src/com/intellij/debugger/engine/JVMNameUtil.java
new file mode 100644
index 0000000..edee6bb
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/JVMNameUtil.java
@@ -0,0 +1,429 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerManager;
+import com.intellij.debugger.SourcePosition;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.progress.ProcessCanceledException;
+import com.intellij.openapi.util.Computable;
+import com.intellij.openapi.util.Ref;
+import com.intellij.psi.*;
+import com.intellij.psi.jsp.JspFile;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.PsiUtil;
+import com.intellij.psi.util.TypeConversionUtil;
+import com.sun.jdi.ReferenceType;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * User: lex
+ * Date: Sep 2, 2003
+ * Time: 11:25:59 AM
+ */
+public class JVMNameUtil {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.JVMNameUtil");
+
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  public static String getPrimitiveSignature(String typeName) {
+    if(PsiType.BOOLEAN.getCanonicalText().equals(typeName)) {
+      return "Z";
+    }
+    else if (PsiType.BYTE.getCanonicalText().equals(typeName)) {
+      return "B";
+    }
+    else if (PsiType.CHAR.getCanonicalText().equals(typeName)) {
+      return "C";
+    }
+    else if (PsiType.SHORT.getCanonicalText().equals(typeName)) {
+      return "S";
+    }
+    else if (PsiType.INT.getCanonicalText().equals(typeName)) {
+      return "I";
+    }
+    else if (PsiType.LONG.getCanonicalText().equals(typeName)) {
+      return "J";
+    }
+    else if (PsiType.FLOAT.getCanonicalText().equals(typeName)) {
+      return "F";
+    }
+    else if (PsiType.DOUBLE.getCanonicalText().equals(typeName)) {
+      return "D";
+    }
+    else if (PsiType.VOID.getCanonicalText().equals(typeName)) {
+      return "V";
+    }
+    return null;
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  private static void appendJVMSignature(JVMNameBuffer buffer , PsiType type){
+    if (type == null) {
+      return;
+    }
+    final PsiType psiType = TypeConversionUtil.erasure(type);
+    if (psiType instanceof PsiArrayType) {
+      buffer.append(new JVMRawText("["));
+      appendJVMSignature(buffer, ((PsiArrayType) psiType).getComponentType());
+    }
+    else if (psiType instanceof PsiClassType) {
+      final JVMName jvmName = getJVMQualifiedName(psiType);
+      appendJvmClassQualifiedName(buffer, jvmName);
+    }
+    else if (psiType instanceof PsiPrimitiveType) {
+      buffer.append(getPrimitiveSignature(psiType.getCanonicalText()));
+    }
+    else {
+      LOG.error("unknown type " + type.getCanonicalText());
+    }
+  }
+
+  private static void appendJvmClassQualifiedName(JVMNameBuffer buffer, final JVMName jvmName) {
+    buffer.append("L");
+    if(jvmName instanceof JVMRawText) {
+      buffer.append(((JVMRawText)jvmName).getName().replace('.','/'));
+    }
+    else {
+      buffer.append(new JVMName() {
+        public String getName(DebugProcessImpl process) throws EvaluateException {
+          return jvmName.getName(process).replace('.','/');
+        }
+
+        public String getDisplayName(DebugProcessImpl debugProcess) {
+          return jvmName.getDisplayName(debugProcess);
+        }
+      });
+    }
+    buffer.append(";");
+  }
+
+  private static class JVMNameBuffer {
+    List<JVMName> myList = new ArrayList<JVMName>();
+
+    public void append(@NotNull JVMName evaluator){
+      myList.add(evaluator);
+    }
+
+    public void append(char name){
+      append(Character.toString(name));
+    }
+
+    public void append(String text){
+      myList.add(getJVMRawText(text));
+    }
+
+    public JVMName toName() {
+      final List<JVMName> optimised = new ArrayList<JVMName>();
+      for (JVMName evaluator : myList) {
+        if (evaluator instanceof JVMRawText && !optimised.isEmpty() && optimised.get(optimised.size() - 1) instanceof JVMRawText) {
+          JVMRawText nameEvaluator = (JVMRawText)optimised.get(optimised.size() - 1);
+          nameEvaluator.setName(nameEvaluator.getName() + ((JVMRawText)evaluator).getName());
+        }
+        else {
+          optimised.add(evaluator);
+        }
+      }
+
+      if(optimised.size() == 1) return optimised.get(0);
+      if(optimised.isEmpty()) return new JVMRawText("");
+
+      return new JVMName() {
+        String myName = null;
+        public String getName(DebugProcessImpl process) throws EvaluateException {
+          if(myName == null){
+            String name = "";
+            for (JVMName nameEvaluator : optimised) {
+              name += nameEvaluator.getName(process);
+            }
+            myName = name;
+          }
+          return myName;
+        }
+
+        public String getDisplayName(DebugProcessImpl debugProcess) {
+          if(myName == null) {
+            String displayName = "";
+            for (JVMName nameEvaluator : optimised) {
+              displayName += nameEvaluator.getDisplayName(debugProcess);
+            }
+            return displayName;
+          }
+          return myName;
+        }
+      };
+    }
+  }
+
+  private static class JVMRawText implements JVMName {
+    private String myText;
+
+    public JVMRawText(String text) {
+      myText = text;
+    }
+
+    public String getName(DebugProcessImpl process) throws EvaluateException {
+      return myText;
+    }
+
+    public String getDisplayName(DebugProcessImpl debugProcess) {
+      return myText;
+    }
+
+    public String getName() {
+      return myText;
+    }
+
+    public void setName(String name) {
+      myText = name;
+    }
+  }
+
+  private static class JVMClassAt implements JVMName {
+    private final SourcePosition mySourcePosition;
+
+    public JVMClassAt(SourcePosition sourcePosition) {
+      mySourcePosition = sourcePosition;
+    }
+
+    public String getName(DebugProcessImpl process) throws EvaluateException {
+      List<ReferenceType> allClasses = process.getPositionManager().getAllClasses(mySourcePosition);
+      if(!allClasses.isEmpty()) {
+        return allClasses.get(0).name();
+      }
+
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("error.class.not.loaded", getDisplayName(process)));
+    }
+
+    public String getDisplayName(final DebugProcessImpl debugProcess) {
+      return ApplicationManager.getApplication().runReadAction(new Computable<String>() {
+        public String compute() {
+          return getSourcePositionClassDisplayName(debugProcess, mySourcePosition);
+        }
+      });
+    }
+  }
+
+  public static JVMName getJVMRawText(String qualifiedName) {
+    return new JVMRawText(qualifiedName);
+  }
+
+  public static JVMName getJVMQualifiedName(PsiType psiType) {
+    if(psiType instanceof PsiArrayType) {
+      final PsiArrayType arrayType = (PsiArrayType)psiType;
+      JVMName jvmName = getJVMQualifiedName(arrayType.getComponentType());
+      JVMNameBuffer buffer = new JVMNameBuffer();
+      buffer.append(jvmName);
+      buffer.append("[]");
+      return buffer.toName();
+    }
+
+    PsiClass psiClass = PsiUtil.resolveClassInType(psiType);
+    if (psiClass == null) {
+      return getJVMRawText(psiType.getCanonicalText());
+    } 
+    else {
+      return getJVMQualifiedName(psiClass);
+    }
+  }
+                               
+  public static JVMName getJVMQualifiedName(PsiClass psiClass) {
+    if (!PsiUtil.isLocalOrAnonymousClass(psiClass)) {
+      final String name = getNonAnonymousClassName(psiClass);
+      if (name != null) {
+        return getJVMRawText(name);
+      }
+    }
+    return new JVMClassAt(SourcePosition.createFromElement(psiClass));
+  }
+
+  @Nullable
+  public static JVMName getContextClassJVMQualifiedName(@Nullable SourcePosition pos) {
+    if (pos == null) {
+      return null;
+    }
+    final PsiClass psiClass = getClassAt(pos);
+    if (psiClass == null) {
+      return null;
+    }
+    if (!PsiUtil.isLocalOrAnonymousClass(psiClass)) {
+      final String name = getNonAnonymousClassName(psiClass);
+      if (name != null) {
+        return getJVMRawText(name);
+      }
+    }
+    return new JVMClassAt(pos);
+  }
+
+  @Nullable
+  public static String getNonAnonymousClassName(PsiClass aClass) {
+    PsiClass parentClass = PsiTreeUtil.getParentOfType(aClass, PsiClass.class, true);
+    if(parentClass != null) {
+      final String parentName = getNonAnonymousClassName(parentClass);
+      if (parentName == null) {
+        return null;
+      }
+      return parentName + "$" + aClass.getName();
+    }
+    return DebuggerManager.getInstance(aClass.getProject()).getVMClassQualifiedName(aClass);
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  public static JVMName getJVMSignature(PsiMethod method) {
+    JVMNameBuffer signature = new JVMNameBuffer();
+    signature.append("(");
+    
+    if (method.isConstructor()) {
+      final PsiClass declaringClass = method.getContainingClass();
+      if (declaringClass != null) {
+        final PsiClass outerClass = declaringClass.getContainingClass();
+        if (outerClass != null) {
+          // declaring class is an inner class
+          if (!declaringClass.hasModifierProperty(PsiModifier.STATIC)) {
+            appendJvmClassQualifiedName(signature, getJVMQualifiedName(outerClass));
+          }
+        }
+      }
+    }
+    for (PsiParameter psiParameter : method.getParameterList().getParameters()) {
+      appendJVMSignature(signature, psiParameter.getType());
+    }
+    signature.append(")");
+    if (!method.isConstructor()) {
+      appendJVMSignature(signature, method.getReturnType());
+    }
+    else {
+      signature.append(new JVMRawText("V"));
+    }
+    return signature.toName();
+  }
+
+  @Nullable
+  public static PsiClass getClassAt(SourcePosition position) {
+    final PsiElement element = position.getElementAt();
+    return (element != null) ? PsiTreeUtil.getParentOfType(element, PsiClass.class, false) : null;
+  }
+
+  @Nullable
+  public static String getSourcePositionClassDisplayName(DebugProcessImpl debugProcess, SourcePosition position) {
+    if (position == null) {
+      return null;
+    }
+    final PsiFile positionFile = position.getFile();
+    if (positionFile instanceof JspFile) {
+      return positionFile.getName();
+    }
+
+    final PsiClass psiClass = getClassAt(position);
+
+    if(psiClass != null) {
+      final String qName = psiClass.getQualifiedName();
+      if(qName != null) {
+        return qName;
+      }
+    }
+
+    if(debugProcess != null && debugProcess.isAttached()) {
+      List<ReferenceType> allClasses = debugProcess.getPositionManager().getAllClasses(position);
+      if(!allClasses.isEmpty()) {
+        return allClasses.get(0).name();
+      }
+    }
+    if (psiClass == null) {
+      if (positionFile instanceof PsiClassOwner) {
+        return positionFile.getName();
+      }
+
+      return DebuggerBundle.message("string.file.line.position", positionFile.getName(), position.getLine());
+    }
+    return calcClassDisplayName(psiClass);
+  }
+
+  static String calcClassDisplayName(final PsiClass aClass) {
+    final String qName = aClass.getQualifiedName();
+    if (qName != null)  {
+      return qName;
+    }
+    final PsiClass parent = PsiTreeUtil.getParentOfType(aClass, PsiClass.class, true);
+    if (parent == null) {
+      return null;
+    }
+    
+    final String name = aClass.getName();
+    if (name != null) {
+      return calcClassDisplayName(parent) + "$" + name;
+    }
+    
+    final Ref<Integer> classIndex = new Ref<Integer>(0);
+    try {
+        parent.accept(new JavaRecursiveElementVisitor() {
+          public void visitAnonymousClass(PsiAnonymousClass cls) {
+            classIndex.set(classIndex.get() + 1);
+            if (aClass.equals(cls)) {
+              throw new ProcessCanceledException();
+            }
+          }
+        });
+      }
+      catch (ProcessCanceledException ignored) {
+      }
+    return calcClassDisplayName(parent) + "$" + classIndex.get();
+  }
+
+  @Nullable
+  public static String getSourcePositionPackageDisplayName(DebugProcessImpl debugProcess, SourcePosition position) {
+    if (position == null) {
+      return null;
+    }
+    final PsiFile positionFile = position.getFile();
+    if (positionFile instanceof JspFile) {
+      final PsiDirectory dir = positionFile.getContainingDirectory();
+      return dir != null? dir.getVirtualFile().getPresentableUrl() : null;
+    }
+
+    final PsiClass psiClass = getClassAt(position);
+
+    if(psiClass != null) {
+      PsiClass toplevel = PsiUtil.getTopLevelClass(psiClass);
+      if(toplevel != null) {
+        String qName = toplevel.getQualifiedName();
+        if (qName != null) {
+          int i = qName.lastIndexOf('.');
+          return i > 0 ? qName.substring(0, i) : "";
+        }
+      }
+    }
+
+    if(debugProcess != null && debugProcess.isAttached()) {
+      List<ReferenceType> allClasses = debugProcess.getPositionManager().getAllClasses(position);
+      if(!allClasses.isEmpty()) {
+        final String className = allClasses.get(0).name();
+        int dotIndex = className.lastIndexOf('.');
+        if (dotIndex >= 0) {
+          return className.substring(0, dotIndex);
+        }
+      }
+    }
+    return "";
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java
new file mode 100644
index 0000000..4909e74
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java
@@ -0,0 +1,368 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine;
+
+import com.intellij.debugger.NoDataException;
+import com.intellij.debugger.PositionManager;
+import com.intellij.debugger.SourcePosition;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
+import com.intellij.debugger.requests.ClassPrepareRequestor;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.DumbService;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.NullableComputable;
+import com.intellij.openapi.util.Ref;
+import com.intellij.openapi.util.Trinity;
+import com.intellij.psi.*;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.util.PsiUtil;
+import com.sun.jdi.AbsentInformationException;
+import com.sun.jdi.Location;
+import com.sun.jdi.ReferenceType;
+import com.sun.jdi.request.ClassPrepareRequest;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @author lex
+ */
+public class PositionManagerImpl implements PositionManager {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.PositionManagerImpl");
+
+  private final DebugProcessImpl myDebugProcess;
+
+  public PositionManagerImpl(DebugProcessImpl debugProcess) {
+    myDebugProcess = debugProcess;
+  }
+
+  public DebugProcess getDebugProcess() {
+    return myDebugProcess;
+  }
+
+  @NotNull
+  public List<Location> locationsOfLine(ReferenceType type, SourcePosition position) throws NoDataException {
+    try {
+      final int line = position.getLine() + 1;
+      return type.locationsOfLine(DebugProcess.JAVA_STRATUM, null, line);
+    }
+    catch (AbsentInformationException ignored) {
+    }
+    return Collections.emptyList();
+  }
+
+  public ClassPrepareRequest createPrepareRequest(final ClassPrepareRequestor requestor, final SourcePosition position) throws NoDataException {
+    final Ref<String> waitPrepareFor = new Ref<String>(null);
+    final Ref<ClassPrepareRequestor> waitRequestor = new Ref<ClassPrepareRequestor>(null);
+    ApplicationManager.getApplication().runReadAction(new Runnable() {
+      public void run() {
+        PsiClass psiClass = JVMNameUtil.getClassAt(position);
+        if (psiClass == null) {
+          return;
+        }
+
+        if (PsiUtil.isLocalOrAnonymousClass(psiClass)) {
+          PsiClass parent = TopLevelParentClassProvider.getTopLevelParentClass(psiClass);
+
+          if (parent == null) {
+            return;
+          }
+
+          final String parentQName = JVMNameUtil.getNonAnonymousClassName(parent);
+          if (parentQName == null) {
+            return;
+          }
+          waitPrepareFor.set(parentQName + "$*");
+          waitRequestor.set(new ClassPrepareRequestor() {
+            public void processClassPrepare(DebugProcess debuggerProcess, ReferenceType referenceType) {
+              final CompoundPositionManager positionManager = ((DebugProcessImpl)debuggerProcess).getPositionManager();
+              final List<ReferenceType> positionClasses = positionManager.getAllClasses(position);
+              if (positionClasses.isEmpty()) {
+                // fallback
+                if (positionManager.locationsOfLine(referenceType, position).size() > 0) {
+                  requestor.processClassPrepare(debuggerProcess, referenceType);
+                }
+              }
+              else {
+                if (positionClasses.contains(referenceType)) {
+                  requestor.processClassPrepare(debuggerProcess, referenceType);
+                }
+              }
+            }
+          });
+        }
+        else {
+          waitPrepareFor.set(JVMNameUtil.getNonAnonymousClassName(psiClass));
+          waitRequestor.set(requestor);
+        }
+      }
+    });
+    if (waitPrepareFor.get() == null) {
+      return null;  // no suitable class found for this name
+    }
+    return myDebugProcess.getRequestsManager().createClassPrepareRequest(waitRequestor.get(), waitPrepareFor.get());
+  }
+
+  public SourcePosition getSourcePosition(final Location location) throws NoDataException {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    if(location == null) {
+      return null;
+    }
+
+    PsiFile psiFile = getPsiFileByLocation(getDebugProcess().getProject(), location);
+    if(psiFile == null ) {
+      return null;
+    }
+
+    LOG.assertTrue(myDebugProcess != null);
+    if (location == null) {
+      return SourcePosition.createFromLine(psiFile, -1);
+    }
+
+    int lineNumber;
+    try {
+      lineNumber = location.lineNumber() - 1;
+    }
+    catch (InternalError e) {
+      lineNumber = -1;
+    }
+
+    if (psiFile instanceof PsiCompiledElement || lineNumber < 0) {
+      final String methodSignature = location.method().signature();
+      if (methodSignature == null) {
+        return SourcePosition.createFromLine(psiFile, -1);
+      }
+      final String methodName = location.method().name();
+      if(methodName == null) {
+        return SourcePosition.createFromLine(psiFile, -1);
+      }
+      if(location.declaringType() == null) {
+        return SourcePosition.createFromLine(psiFile, -1);
+      }
+
+      final MethodFinder finder = new MethodFinder(location.declaringType().name(), methodSignature);
+      psiFile.accept(finder);
+
+      final PsiMethod compiledMethod = finder.getCompiledMethod();
+      if (compiledMethod == null) {
+        return SourcePosition.createFromLine(psiFile, -1);
+      }
+      return SourcePosition.createFromElement(compiledMethod);
+    }
+
+    return SourcePosition.createFromLine(psiFile, lineNumber);
+  }
+
+  @Nullable
+  private PsiFile getPsiFileByLocation(final Project project, final Location location) {
+    if (location == null) {
+      return null;
+    }
+    final ReferenceType refType = location.declaringType();
+    if (refType == null) {
+      return null;
+    }
+
+    if (DumbService.getInstance(project).isDumb()) {
+      return null;
+    }
+
+    final String originalQName = refType.name();
+    int dollar = originalQName.indexOf('$');
+    final String qName = dollar >= 0 ? originalQName.substring(0, dollar) : originalQName;
+    final GlobalSearchScope searchScope = myDebugProcess.getSearchScope();
+    PsiClass psiClass = DebuggerUtils.findClass(qName, project, searchScope);
+    if (psiClass == null && dollar >= 0 /*originalName and qName really differ*/) {
+      psiClass = DebuggerUtils.findClass(originalQName, project, searchScope); // try to lookup original name
+    }
+    
+    if (psiClass != null) {
+      final PsiElement element = psiClass.getNavigationElement();
+      return element.getContainingFile();
+    }
+
+    return null;
+  }
+
+  @NotNull
+  public List<ReferenceType> getAllClasses(final SourcePosition classPosition) throws NoDataException {
+    final Trinity<String, Boolean, PsiClass> trinity = calcClassName(classPosition);
+    if (trinity == null) {
+      return Collections.emptyList();
+    }
+    final String className = trinity.getFirst();
+    final boolean isNonAnonymousClass = trinity.getSecond();
+    final PsiClass classAtPosition = trinity.getThird();
+
+    if (isNonAnonymousClass) {
+      return myDebugProcess.getVirtualMachineProxy().classesByName(className);
+    }
+    
+    // the name is a parent class for a local or anonymous class
+    final List<ReferenceType> outers = myDebugProcess.getVirtualMachineProxy().classesByName(className);
+    final List<ReferenceType> result = new ArrayList<ReferenceType>(outers.size());
+    for (ReferenceType outer : outers) {
+      final ReferenceType nested = findNested(outer, classAtPosition, classPosition);
+      if (nested != null) {
+        result.add(nested);
+      }
+    }
+    return result;
+  }
+
+  @Nullable
+  private static Trinity<String, Boolean, PsiClass> calcClassName(final SourcePosition classPosition) {
+    return ApplicationManager.getApplication().runReadAction(new NullableComputable<Trinity<String, Boolean, PsiClass>>() {
+      public Trinity<String, Boolean, PsiClass> compute() {
+        final PsiClass psiClass = JVMNameUtil.getClassAt(classPosition);
+
+        if(psiClass == null) {
+          return null;
+        }
+
+        if(PsiUtil.isLocalOrAnonymousClass(psiClass)) {
+          final PsiClass parentNonLocal = TopLevelParentClassProvider.getTopLevelParentClass(psiClass);
+          if(parentNonLocal == null) {
+            LOG.error("Local or anonymous class has no non-local parent");
+            return null;
+          }
+          final String parentClassName = JVMNameUtil.getNonAnonymousClassName(parentNonLocal);
+          if(parentClassName == null) {
+            LOG.error("The name of a parent of a local (anonymous) class is null");
+            return null;
+          }
+          return new Trinity<String, Boolean, PsiClass>(parentClassName, Boolean.FALSE, psiClass);
+        }
+        
+        final String className = JVMNameUtil.getNonAnonymousClassName(psiClass);
+        return className != null? new Trinity<String, Boolean, PsiClass>(className, Boolean.TRUE, psiClass) : null;
+      }
+    });
+  }
+
+  @Nullable
+  private ReferenceType findNested(final ReferenceType fromClass, final PsiClass classToFind, SourcePosition classPosition) {
+    final VirtualMachineProxyImpl vmProxy = myDebugProcess.getVirtualMachineProxy();
+    if (fromClass.isPrepared()) {
+      
+      final List<ReferenceType> nestedTypes = vmProxy.nestedTypes(fromClass);
+      
+      try {
+        final int lineNumber = classPosition.getLine() + 1;
+
+        for (ReferenceType nested : nestedTypes) {
+          final ReferenceType found = findNested(nested, classToFind, classPosition);
+          if (found != null) {
+            // check if enclosing class also has executable code at the same line, and if yes, prefer enclosing class 
+            return fromClass.locationsOfLine(lineNumber).isEmpty()? found : fromClass;
+          }
+        }
+
+        if (fromClass.locationsOfLine(lineNumber).size() > 0) {
+          return fromClass;
+        }
+        
+        int rangeBegin = Integer.MAX_VALUE;
+        int rangeEnd = Integer.MIN_VALUE;
+        for (Location location : fromClass.allLineLocations()) {
+          final int locationLine = location.lineNumber() - 1;
+          rangeBegin = Math.min(rangeBegin,  locationLine);
+          rangeEnd = Math.max(rangeEnd,  locationLine);
+        }
+
+        if (classPosition.getLine() >= rangeBegin && classPosition.getLine() <= rangeEnd) {
+          // choose the second line to make sure that only this class' code exists on the line chosen
+          // Otherwise the line (depending on the offset in it) can contain code that belongs to different classes
+          // and JVMNameUtil.getClassAt(candidatePosition) will return the wrong class.
+          // Example of such line:
+          // list.add(new Runnable(){......
+          // First offsets belong to parent class, and offsets inside te substring "new Runnable(){" belong to anonymous runnable.
+          final int finalRangeBegin = rangeBegin;
+          final int finalRangeEnd = rangeEnd;
+          return ApplicationManager.getApplication().runReadAction(new NullableComputable<ReferenceType>() {
+            public ReferenceType compute() {
+              if (!classToFind.isValid()) {
+                return null;
+              }
+              final int line = Math.min(finalRangeBegin + 1, finalRangeEnd);
+              final SourcePosition candidatePosition = SourcePosition.createFromLine(classToFind.getContainingFile(), line);
+              return classToFind.equals(JVMNameUtil.getClassAt(candidatePosition)) ? fromClass : null;
+            }
+          });
+        }
+      }
+      catch (AbsentInformationException ignored) {
+      }
+    }
+    return null;
+  }
+
+  //don't use JavaRecursiveElementWalkingVisitor because getNextSibling() works slowly for compiled elements 
+  private class MethodFinder extends JavaRecursiveElementVisitor {
+    private final String myClassName;
+    private PsiClass myCompiledClass;
+    private final String myMethodSignature;
+    private PsiMethod myCompiledMethod;
+
+    public MethodFinder(final String className, final String methodSignature) {
+      myClassName = className;
+      myMethodSignature = methodSignature;
+    }
+
+    @Override public void visitClass(PsiClass aClass) {
+      final List<ReferenceType> allClasses = myDebugProcess.getPositionManager().getAllClasses(SourcePosition.createFromElement(aClass));
+      for (ReferenceType referenceType : allClasses) {
+        if (referenceType.name().equals(myClassName)) {
+          myCompiledClass = aClass;
+        }
+      }
+
+      aClass.acceptChildren(this);
+    }
+
+    @Override public void visitMethod(PsiMethod method) {
+      try {
+        //noinspection HardCodedStringLiteral
+        String methodName = method.isConstructor() ? "<init>" : method.getName();
+        PsiClass containingClass = method.getContainingClass();
+
+        if(containingClass != null &&
+           containingClass.equals(myCompiledClass) &&
+           methodName.equals(methodName) &&
+           JVMNameUtil.getJVMSignature(method).getName(myDebugProcess).equals(myMethodSignature)) {
+
+          myCompiledMethod = method;
+        }
+      }
+      catch (EvaluateException e) {
+        LOG.debug(e);
+      }
+    }
+
+    public PsiClass getCompiledClass() {
+      return myCompiledClass;
+    }
+
+    public PsiMethod getCompiledMethod() {
+      return myCompiledMethod;
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/RemoteDebugProcessHandler.java b/java/debugger/impl/src/com/intellij/debugger/engine/RemoteDebugProcessHandler.java
new file mode 100644
index 0000000..84e3032
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/RemoteDebugProcessHandler.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine;
+
+import com.intellij.debugger.DebuggerManager;
+import com.intellij.execution.process.ProcessHandler;
+import com.intellij.openapi.project.Project;
+
+import java.io.OutputStream;
+
+public class RemoteDebugProcessHandler extends ProcessHandler{
+  private final Project myProject;
+
+  public RemoteDebugProcessHandler(Project project) {
+    myProject = project;
+  }
+
+  public void startNotify() {
+    final DebugProcess debugProcess = DebuggerManager.getInstance(myProject).getDebugProcess(this);
+    final DebugProcessAdapter listener = new DebugProcessAdapter() {
+      //executed in manager thread
+      public void processDetached(DebugProcess process, boolean closedByUser) {
+        debugProcess.removeDebugProcessListener(this);
+        notifyProcessDetached();
+      }
+    };
+    debugProcess.addDebugProcessListener(listener);
+    try {
+      super.startNotify();
+    }
+    finally {
+      // in case we added our listener too late, we may have lost processDetached notification,
+      // so check here if process is detached
+      if (debugProcess.isDetached()) {
+        debugProcess.removeDebugProcessListener(listener);
+        notifyProcessDetached();
+      }
+    }
+  }
+
+  protected void destroyProcessImpl() {
+    DebugProcess debugProcess = DebuggerManager.getInstance(myProject).getDebugProcess(this);
+    if(debugProcess != null) {
+      debugProcess.stop(true);
+    }
+  }
+
+  protected void detachProcessImpl() {
+    DebugProcess debugProcess = DebuggerManager.getInstance(myProject).getDebugProcess(this);
+    if(debugProcess != null) {
+      debugProcess.stop(false);
+    }
+  }
+
+  public boolean detachIsDefault() {
+    return true;
+  }
+
+  public OutputStream getProcessInput() {
+    return null;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/RemoteStateState.java b/java/debugger/impl/src/com/intellij/debugger/engine/RemoteStateState.java
new file mode 100644
index 0000000..4205f24
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/RemoteStateState.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine;
+
+import com.intellij.execution.DefaultExecutionResult;
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.ExecutionResult;
+import com.intellij.execution.Executor;
+import com.intellij.execution.configurations.ConfigurationPerRunnerSettings;
+import com.intellij.execution.configurations.RemoteConnection;
+import com.intellij.execution.configurations.RemoteState;
+import com.intellij.execution.configurations.RunnerSettings;
+import com.intellij.execution.impl.ConsoleViewImpl;
+import com.intellij.execution.runners.ProgramRunner;
+import com.intellij.openapi.project.Project;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author lex
+ */
+public class RemoteStateState implements RemoteState {
+  private final Project    myProject;
+  private final RemoteConnection myConnection;
+  private final RunnerSettings myRunnerSettings;
+  private final ConfigurationPerRunnerSettings myConfigurationSettings;
+
+  public RemoteStateState(Project project,
+                          RemoteConnection connection,
+                          RunnerSettings runnerSettings,
+                          ConfigurationPerRunnerSettings configurationSettings) {
+    myProject = project;
+    myConnection = connection;
+    myRunnerSettings = runnerSettings;
+    myConfigurationSettings = configurationSettings;
+  }
+
+  public RunnerSettings getRunnerSettings() {
+    return myRunnerSettings;
+  }
+
+  public ConfigurationPerRunnerSettings getConfigurationSettings() {
+    return myConfigurationSettings;
+  }
+
+  public ExecutionResult execute(final Executor executor, @NotNull final ProgramRunner runner) throws ExecutionException {
+    ConsoleViewImpl consoleView = new ConsoleViewImpl(myProject, false);
+    RemoteDebugProcessHandler process = new RemoteDebugProcessHandler(myProject);
+    consoleView.attachToProcess(process);
+    return new DefaultExecutionResult(consoleView, process);
+  }
+
+  public RemoteConnection getRemoteConnection() {
+    return myConnection;
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/RequestHint.java b/java/debugger/impl/src/com/intellij/debugger/engine/RequestHint.java
new file mode 100644
index 0000000..1a94cbc
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/RequestHint.java
@@ -0,0 +1,297 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * @author: Eugene Zhuravlev
+ * Date: Jul 23, 2002
+ * Time: 11:10:11 AM
+ */
+package com.intellij.debugger.engine;
+
+import com.intellij.debugger.SourcePosition;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.jdi.StackFrameProxy;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.impl.PositionUtil;
+import com.intellij.debugger.jdi.StackFrameProxyImpl;
+import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
+import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
+import com.intellij.debugger.settings.DebuggerSettings;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.Computable;
+import com.intellij.psi.PsiMethod;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.sun.jdi.*;
+import com.sun.jdi.request.StepRequest;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class RequestHint {
+  public static final int STOP = 0;
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.RequestHint");
+  private final int myDepth;
+  private SourcePosition myPosition;
+  private int myFrameCount;
+  private VirtualMachineProxyImpl myVirtualMachineProxy;
+
+  private final @Nullable SmartStepFilter myTargetMethodSignature;
+  private boolean myIgnoreFilters = false;
+  private boolean myRestoreBreakpoints = false;
+  private final boolean mySkipThisMethod = false;
+
+  public static final class SmartStepFilter {
+    private final JVMName myDeclaringClassName;
+    private final @NonNls String myTargetMethodName;
+    private final JVMName myTargetMethodSignature;
+    private boolean myMethodExecuted;
+
+    public SmartStepFilter(PsiMethod psiMethod) {
+      this(JVMNameUtil.getJVMQualifiedName(psiMethod.getContainingClass()),
+           psiMethod.isConstructor()? "<init>" : psiMethod.getName(),
+           JVMNameUtil.getJVMSignature(psiMethod));
+    }
+
+    public SmartStepFilter(@NotNull JVMName declaringClassName, @NonNls String targetMethodName,
+                           @NotNull JVMName targetMethodSignature) {
+      myDeclaringClassName = declaringClassName;
+      myTargetMethodName = targetMethodName;
+      myTargetMethodSignature = targetMethodSignature;
+    }
+
+    public String getTargetMethodName() {
+      return myTargetMethodName;
+    }
+
+    public boolean wasMethodExecuted() {
+      return myMethodExecuted;
+    }
+
+    public boolean shouldStopAtLocation(final SuspendContextImpl context) {
+      try {
+        final StackFrameProxyImpl frameProxy = context.getFrameProxy();
+        if (frameProxy == null) {
+          return true;
+        }
+        final Location location = frameProxy.location();
+        final Method method = location.method();
+        if (!myTargetMethodName.equals(method.name())) {
+          return false;
+        }
+        final DebugProcessImpl process = context.getDebugProcess();
+        if (!signatureMatches(method, myTargetMethodSignature.getName(process))) {
+          return false;
+        }
+        myMethodExecuted = true;
+        final ObjectReference thisObject = frameProxy.thisObject();
+        final ReferenceType locationClass = thisObject != null? thisObject.referenceType() : method.declaringType();
+        return DebuggerUtilsEx.isAssignableFrom(myDeclaringClassName.getName(process), locationClass);
+      }
+      catch (EvaluateException e) {
+        LOG.info(e);
+      }
+      return true;
+    }
+
+    private static boolean signatureMatches(Method method, final String expectedSignature) throws EvaluateException {
+      if (expectedSignature.equals(method.signature())) {
+        return true;
+      }
+      // check if there are any bridge methods that match
+      for (Method candidate : method.declaringType().methodsByName(method.name())) {
+        if (candidate != method && candidate.isBridge() && expectedSignature.equals(candidate.signature())) {
+          return true;
+        }
+      }
+      return false;
+    }
+  }
+
+  public RequestHint(final ThreadReferenceProxyImpl stepThread, final SuspendContextImpl suspendContext, @NotNull SmartStepFilter smartStepFilter) {
+    this(stepThread, suspendContext, StepRequest.STEP_INTO, smartStepFilter);
+  }
+
+  public RequestHint(final ThreadReferenceProxyImpl stepThread, final SuspendContextImpl suspendContext, int depth) {
+    this(stepThread, suspendContext, depth, null);
+  }
+
+  private RequestHint(final ThreadReferenceProxyImpl stepThread, final SuspendContextImpl suspendContext, int depth, SmartStepFilter smartStepFilter) {
+    final DebugProcessImpl debugProcess = suspendContext.getDebugProcess();
+    myDepth = depth;
+    myTargetMethodSignature = smartStepFilter;
+    myVirtualMachineProxy = debugProcess.getVirtualMachineProxy();
+
+    try {
+      myFrameCount = stepThread.frameCount();
+
+      ApplicationManager.getApplication().runReadAction(new Runnable() {
+        public void run() {
+          myPosition = ContextUtil.getSourcePosition(new StackFrameContext() {
+            public StackFrameProxy getFrameProxy() {
+              try {
+                return stepThread.frame(0);
+              }
+              catch (EvaluateException e) {
+                if (LOG.isDebugEnabled()) {
+                  LOG.debug(e);
+                }
+                return null;
+              }
+            }
+
+            public DebugProcess getDebugProcess() {
+              return suspendContext.getDebugProcess();
+            }
+          });
+        }
+      });
+    }
+    catch (Exception e) {
+      myPosition = null;
+    }
+  }
+
+  public void setIgnoreFilters(boolean ignoreFilters) {
+    myIgnoreFilters = ignoreFilters;
+  }
+
+  public void setRestoreBreakpoints(boolean restoreBreakpoints) {
+    myRestoreBreakpoints = restoreBreakpoints;
+  }
+
+  public boolean isRestoreBreakpoints() {
+    return myRestoreBreakpoints;
+  }
+
+  public boolean isIgnoreFilters() {
+    return myIgnoreFilters;
+  }
+
+  public int getDepth() {
+    return mySkipThisMethod ? StepRequest.STEP_OUT : myDepth;
+  }
+
+  @Nullable
+  public SmartStepFilter getSmartStepFilter() {
+    return myTargetMethodSignature;
+  }
+
+  public int getNextStepDepth(final SuspendContextImpl context) {
+    try {
+      if ((myDepth == StepRequest.STEP_OVER || myDepth == StepRequest.STEP_INTO) && myPosition != null) {
+        final Integer resultDepth = ApplicationManager.getApplication().runReadAction(new Computable<Integer>() {
+          public Integer compute() {
+            final SourcePosition locationPosition = ContextUtil.getSourcePosition(context);
+            if (locationPosition == null) {
+              return null;
+            }
+            int frameCount = -1;
+            final ThreadReferenceProxyImpl contextThread = context.getThread();
+            if (contextThread != null) {
+              try {
+                frameCount = contextThread.frameCount();
+              }
+              catch (EvaluateException e) {
+              }
+            }
+            final boolean filesEqual = myPosition.getFile().equals(locationPosition.getFile());
+            if (filesEqual && myPosition.getLine() == locationPosition.getLine() && myFrameCount == frameCount) {
+              return myDepth;
+            }
+            if (myDepth == StepRequest.STEP_INTO) {
+              if (filesEqual) {
+                // we are actually one or more frames upper than the original frame, should stop
+                if (myFrameCount > frameCount) {
+                  return STOP;
+                }
+                // check if we are still at the line from which the stepping begun
+                if (myFrameCount == frameCount && myPosition.getLine() != locationPosition.getLine()) {
+                  return STOP;
+                }
+              }
+            }
+            return null;
+          }
+        });
+        if (resultDepth != null) {
+          return resultDepth.intValue();
+        }
+      }
+      // the rest of the code makes sense for depth == STEP_INTO only
+
+      if (myDepth == StepRequest.STEP_INTO) {
+        final DebuggerSettings settings = DebuggerSettings.getInstance();
+        final StackFrameProxyImpl frameProxy = context.getFrameProxy();
+
+        if (settings.SKIP_SYNTHETIC_METHODS && frameProxy != null) {
+          final Location location = frameProxy.location();
+          final Method method = location.method();
+          if (method != null) {
+            if (myVirtualMachineProxy.canGetSyntheticAttribute()? method.isSynthetic() : method.name().indexOf('$') >= 0) {
+              return myDepth;
+            }
+          }
+        }
+
+        if (!myIgnoreFilters) {
+          if(settings.SKIP_GETTERS) {
+            boolean isGetter = ApplicationManager.getApplication().runReadAction(new Computable<Boolean>(){
+              public Boolean compute() {
+                final PsiMethod psiMethod = PsiTreeUtil.getParentOfType(PositionUtil.getContextElement(context), PsiMethod.class);
+                return (psiMethod != null && DebuggerUtils.isSimpleGetter(psiMethod))? Boolean.TRUE : Boolean.FALSE;
+              }
+            }).booleanValue();
+
+            if(isGetter) {
+              return StepRequest.STEP_OUT;
+            }
+          }
+
+          if (frameProxy != null) {
+            if (settings.SKIP_CONSTRUCTORS) {
+              final Location location = frameProxy.location();
+              final Method method = location.method();
+              if (method != null && method.isConstructor()) {
+                return StepRequest.STEP_OUT;
+              }
+            }
+
+            if (settings.SKIP_CLASSLOADERS) {
+              final Location location = frameProxy.location();
+              if (DebuggerUtilsEx.isAssignableFrom("java.lang.ClassLoader", location.declaringType())) {
+                return StepRequest.STEP_OUT;
+              }
+            }
+          }
+        }
+        // smart step feature
+        if (myTargetMethodSignature != null) {
+          if (!myTargetMethodSignature.shouldStopAtLocation(context)) {
+            return StepRequest.STEP_OUT;
+          }
+        }
+      }
+    }
+    catch (VMDisconnectedException e) {
+    }
+    catch (EvaluateException e) {
+      LOG.error(e);
+    }
+    return STOP;
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/SuspendContextImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/SuspendContextImpl.java
new file mode 100644
index 0000000..4ce8162
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/SuspendContextImpl.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine;
+
+import com.intellij.Patches;
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
+import com.intellij.debugger.jdi.StackFrameProxyImpl;
+import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.util.containers.HashSet;
+import com.sun.jdi.ObjectReference;
+import com.sun.jdi.ThreadReference;
+import com.sun.jdi.event.EventSet;
+import com.sun.jdi.request.EventRequest;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Set;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+/**
+ * @author lex
+ */
+public abstract class SuspendContextImpl implements SuspendContext {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.SuspendContextImpl");
+
+  private final DebugProcessImpl myDebugProcess;
+  private final int mySuspendPolicy;
+
+  private ThreadReferenceProxyImpl myThread;
+  boolean myIsVotedForResume = true;
+
+  protected int myVotesToVote;
+  protected Set<ThreadReferenceProxyImpl> myResumedThreads;
+
+  private final EventSet myEventSet;
+  private volatile boolean  myIsResumed;
+
+  public ConcurrentLinkedQueue<SuspendContextCommandImpl> myPostponedCommands = new ConcurrentLinkedQueue<SuspendContextCommandImpl>();
+  public volatile boolean  myInProgress;
+  private final HashSet<ObjectReference>       myKeptReferences = new HashSet<ObjectReference>();
+  private EvaluationContextImpl          myEvaluationContext = null;
+
+  SuspendContextImpl(@NotNull DebugProcessImpl debugProcess, int suspendPolicy, int eventVotes, EventSet set) {
+    myDebugProcess = debugProcess;
+    mySuspendPolicy = suspendPolicy;
+    myVotesToVote = eventVotes;
+    myEventSet = set;
+  }
+
+  public void setThread(ThreadReference thread) {
+    assertNotResumed();
+    ThreadReferenceProxyImpl threadProxy = myDebugProcess.getVirtualMachineProxy().getThreadReferenceProxy(thread);
+    LOG.assertTrue(myThread == null || myThread == threadProxy);
+    myThread = threadProxy;
+  }
+
+  protected abstract void resumeImpl();
+
+  protected void resume(){
+    assertNotResumed();
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    try {
+      if (!Patches.IBM_JDK_DISABLE_COLLECTION_BUG) {
+        for (ObjectReference objectReference : myKeptReferences) {
+          try {
+            objectReference.enableCollection();
+          }
+          catch (UnsupportedOperationException e) {
+            // ignore: some J2ME implementations does not provide this operation
+          }
+        }
+        myKeptReferences.clear();
+      }
+
+      for(SuspendContextCommandImpl cmd = pollPostponedCommand(); cmd != null; cmd = pollPostponedCommand()) {
+        cmd.notifyCancelled();
+      }
+
+      resumeImpl();
+    }
+    finally {
+      myIsResumed = true;
+    }
+  }
+
+  private void assertNotResumed() {
+    if (myIsResumed) {
+      if (myDebugProcess.isAttached()) {
+        LOG.error("Cannot access SuspendContext. SuspendContext is resumed.");
+      }
+    }
+  }
+
+
+  public EventSet getEventSet() {
+    assertNotResumed();
+    return myEventSet;
+  }
+
+  public DebugProcessImpl getDebugProcess() {
+    assertNotResumed();
+    return myDebugProcess;
+  }
+
+  public StackFrameProxyImpl getFrameProxy() {
+    assertNotResumed();
+    try {
+      return myThread != null && myThread.frameCount() > 0 ? myThread.frame(0) : null;
+    }
+    catch (EvaluateException e) {
+      return null;
+    }
+  }
+
+  public ThreadReferenceProxyImpl getThread() {
+    return myThread;
+  }
+
+  public int getSuspendPolicy() {
+    assertNotResumed();
+    return mySuspendPolicy;
+  }
+
+  public void doNotResumeHack() {
+    assertNotResumed();
+    myVotesToVote = 1000000000;
+  }
+
+  public boolean isExplicitlyResumed(ThreadReferenceProxyImpl thread) {
+    return myResumedThreads != null ? myResumedThreads.contains(thread) : false;
+  }
+
+  public boolean suspends(ThreadReferenceProxyImpl thread) {
+    assertNotResumed();
+    if(isEvaluating()) {
+      return false;
+    }
+    switch(getSuspendPolicy()) {
+      case EventRequest.SUSPEND_ALL:
+        return !isExplicitlyResumed(thread);
+      case EventRequest.SUSPEND_EVENT_THREAD:
+        return thread == getThread();
+    }
+    return false;
+  }
+
+  public boolean isEvaluating() {
+    assertNotResumed();
+    return myEvaluationContext != null;
+  }
+
+  public EvaluationContextImpl getEvaluationContext() {
+    return myEvaluationContext;
+  }
+
+  public boolean isResumed() {
+    return myIsResumed;
+  }
+
+  public void setIsEvaluating(EvaluationContextImpl evaluationContext) {
+    assertNotResumed();
+    myEvaluationContext = evaluationContext;
+  }
+
+  public String toString() {
+    if (myEventSet != null) {
+      return myEventSet.toString();
+    } 
+    return myThread != null ? myThread.toString() : DebuggerBundle.message("string.null.context");
+  }
+
+  public void keep(ObjectReference reference) {
+    if (!Patches.IBM_JDK_DISABLE_COLLECTION_BUG) {
+      final boolean added = myKeptReferences.add(reference);
+      if (added) {
+        try {
+          reference.disableCollection();
+        }
+        catch (UnsupportedOperationException e) {
+          // ignore: some J2ME implementations does not provide this operation
+        }
+      }
+    }
+  }
+
+  public final void postponeCommand(final SuspendContextCommandImpl command) {
+    if (!isResumed()) {
+      // Important! when postponing increment the holds counter, so that the action is not released too early.
+      // This will ensure that the counter becomes zero only when the command is actually executed or canceled
+      command.hold();
+      myPostponedCommands.add(command);
+    }
+    else {
+      command.notifyCancelled();
+    }
+  }
+
+  public final SuspendContextCommandImpl pollPostponedCommand() {
+    return myPostponedCommands.poll();
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/SuspendContextRunnable.java b/java/debugger/impl/src/com/intellij/debugger/engine/SuspendContextRunnable.java
new file mode 100644
index 0000000..6df6a14
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/SuspendContextRunnable.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine;
+
+import com.intellij.debugger.engine.SuspendContextImpl;
+
+public interface SuspendContextRunnable  {
+  void run(SuspendContextImpl suspendContext) throws Exception;
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/SuspendManager.java b/java/debugger/impl/src/com/intellij/debugger/engine/SuspendManager.java
new file mode 100644
index 0000000..92fdd71
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/SuspendManager.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine;
+
+import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
+import com.sun.jdi.ObjectCollectedException;
+import com.sun.jdi.event.EventSet;
+
+import java.util.List;
+
+public interface SuspendManager {
+  SuspendContextImpl pushSuspendContext(EventSet eventSet);
+  SuspendContextImpl pushSuspendContext(int suspendAll, int i);
+
+  void resume(SuspendContextImpl suspendContext);
+
+  //replaces current context with new one at the same location and fires 'paused' event
+  void popFrame(SuspendContextImpl suspendContext);
+
+  SuspendContextImpl getPausedContext();
+  boolean isFrozen(ThreadReferenceProxyImpl thread);
+  boolean isSuspended(ThreadReferenceProxyImpl thread) throws ObjectCollectedException;
+
+  void freezeThread(ThreadReferenceProxyImpl invokeThread);
+  void unfreezeThread(ThreadReferenceProxyImpl thread);
+
+  void resumeThread(SuspendContextImpl suspendContext, ThreadReferenceProxyImpl invokeThread);
+  void suspendThread(SuspendContextImpl suspendContext, ThreadReferenceProxyImpl invokeThread);
+
+  void voteResume(SuspendContextImpl suspendContext);
+  void voteSuspend(SuspendContextImpl suspendContext);
+
+  List<SuspendContextImpl> getEventContexts();
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/SuspendManagerImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/SuspendManagerImpl.java
new file mode 100644
index 0000000..de161f1
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/SuspendManagerImpl.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine;
+
+import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
+import com.intellij.openapi.diagnostic.Logger;
+import com.sun.jdi.InternalException;
+import com.sun.jdi.ObjectCollectedException;
+import com.sun.jdi.event.EventSet;
+import com.sun.jdi.request.EventRequest;
+
+import java.util.*;
+
+/**
+ * @author lex
+ */
+public class SuspendManagerImpl implements SuspendManager {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.SuspendManager");
+
+  private final LinkedList<SuspendContextImpl> myEventContexts  = new LinkedList<SuspendContextImpl>();
+  /**
+   * contexts, paused at breakpoint or another debugger event requests. Note that thread, explicitly paused by user is not considered as
+   * "paused at breakpoint" and JDI prohibits data queries on its stackframes
+   */
+  private final LinkedList<SuspendContextImpl> myPausedContexts = new LinkedList<SuspendContextImpl>();
+  private final Set<ThreadReferenceProxyImpl>  myFrozenThreads  = Collections.synchronizedSet(new HashSet<ThreadReferenceProxyImpl>());
+
+  private final DebugProcessImpl myDebugProcess;
+
+  public int suspends = 0;
+
+  public SuspendManagerImpl(DebugProcessImpl debugProcess) {
+    myDebugProcess = debugProcess;
+    myDebugProcess.addDebugProcessListener(new DebugProcessAdapterImpl() {
+      public void processDetached(DebugProcessImpl process, boolean closedByUser) {
+        myEventContexts.clear();
+        myPausedContexts.clear();
+        myFrozenThreads.clear();
+      }
+    });
+  }
+
+  public SuspendContextImpl pushSuspendContext(final int suspendPolicy, int nVotes) {
+    SuspendContextImpl suspendContext = new SuspendContextImpl(myDebugProcess, suspendPolicy, nVotes, null) {
+      protected void resumeImpl() {
+        if (LOG.isDebugEnabled()) {
+          LOG.debug("Start resuming...");
+        }
+        myDebugProcess.logThreads();
+        switch(getSuspendPolicy()) {
+          case EventRequest.SUSPEND_ALL:
+            int resumeAttempts = 5;
+            while (--resumeAttempts > 0) {
+              try {
+                myDebugProcess.getVirtualMachineProxy().resume();
+                break;
+              }
+              catch (InternalException e) {
+                //InternalException 13 means that there are running threads that we are trying to resume
+                //On MacOS it happened that native thread didn't stop while some java thread reached breakpoint
+                if (/*Patches.MAC_RESUME_VM_HACK && */e.errorCode() == 13) {
+                  //Its funny, but second resume solves the problem
+                  continue;
+                }
+                else {
+                  LOG.error(e);
+                  break;
+                }
+              }
+            }
+            
+            if (LOG.isDebugEnabled()) {
+              LOG.debug("VM resumed ");
+            }
+            break;
+          case EventRequest.SUSPEND_EVENT_THREAD:
+            getThread().resume();
+            if(LOG.isDebugEnabled()) {
+              LOG.debug("Thread resumed : " + getThread().toString());
+            }
+            break;
+          case EventRequest.SUSPEND_NONE:
+            if (LOG.isDebugEnabled()) {
+              LOG.debug("None resumed");
+            }
+            break;
+        }
+        if (LOG.isDebugEnabled()) {
+          LOG.debug("Suspends = " + suspends);
+        }
+        myDebugProcess.logThreads();
+      }
+    };
+    pushContext(suspendContext);
+    return suspendContext;
+  }
+
+  public SuspendContextImpl pushSuspendContext(final EventSet set) {
+    SuspendContextImpl suspendContext = new SuspendContextImpl(myDebugProcess, set.suspendPolicy(), set.size(), set) {
+      protected void resumeImpl() {
+        if (LOG.isDebugEnabled()) {
+          LOG.debug("Start resuming eventSet " + set.toString() + " suspendPolicy = " + set.suspendPolicy() + ",size = " + set.size());
+        }
+        myDebugProcess.logThreads();
+        //final ThreadReferenceProxyImpl thread = getThread();
+        //
+        //if (thread != null) { // check that thread is suspended at the moment
+        //  try {
+        //    if (!thread.isSuspended()) {
+        //      final int status = thread.status();
+        //      if ((status != ThreadReference.THREAD_STATUS_ZOMBIE) && (status != ThreadReference.THREAD_STATUS_NOT_STARTED) && (status != ThreadReference.THREAD_STATUS_UNKNOWN)) {
+        //        LOG.error("Context thread must be suspended");
+        //      }
+        //    }
+        //  }
+        //  catch (ObjectCollectedException ignored) {}
+        //}
+
+        int attempts = 5;
+        while (--attempts > 0) {
+          try {
+            set.resume();
+            break;
+          }
+          catch (ObjectCollectedException e) {
+            // according to error reports set.resume() may throw this if one of the threads has been collected
+            LOG.info(e);
+            continue;
+          }
+          catch (InternalException e) {
+            //InternalException 13 means that there are running threads that we are trying to resume
+            //On MacOS it happened that native thread didn't stop while some java thread reached breakpoint
+            if (/*Patches.MAC_RESUME_VM_HACK && */e.errorCode() == 13 && set.suspendPolicy() == EventRequest.SUSPEND_ALL) {
+              //Its funny, but second resume solves the problem
+              continue;
+            }
+            else {
+              LOG.error(e);
+              break;
+            }
+          }
+        }
+        if (LOG.isDebugEnabled()) {
+          LOG.debug("Set resumed ");
+        }
+        myDebugProcess.logThreads();
+      }
+    };
+    pushContext(suspendContext);
+    return suspendContext;
+  }
+
+  private void pushContext(SuspendContextImpl suspendContext) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    myEventContexts.addFirst(suspendContext);
+    suspends++;
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("Push context : Suspends = " + suspends);
+    }
+  }
+
+  public void resume(SuspendContextImpl context) {
+    SuspendManagerUtil.prepareForResume(context);
+
+    myDebugProcess.logThreads();
+    final int suspendPolicy = context.getSuspendPolicy();
+    popContext(context);
+    context.resume();
+    myDebugProcess.clearCashes(suspendPolicy);
+  }
+
+  public void popFrame(SuspendContextImpl suspendContext) {
+    popContext(suspendContext);
+    SuspendContextImpl newSuspendContext = pushSuspendContext(suspendContext.getSuspendPolicy(), 0);
+    newSuspendContext.setThread(suspendContext.getThread().getThreadReference());
+    notifyPaused(newSuspendContext);
+  }
+
+  public SuspendContextImpl getPausedContext() {
+    return !myPausedContexts.isEmpty() ? myPausedContexts.getFirst() : null;
+  }
+
+  public void popContext(SuspendContextImpl suspendContext) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    suspends--;
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("popContext, suspends = " + suspends);
+    }
+    myEventContexts.remove(suspendContext);
+    myPausedContexts.remove(suspendContext);
+  }
+
+  void pushPausedContext(SuspendContextImpl suspendContext) {
+    if(LOG.isDebugEnabled()) {
+      LOG.assertTrue(myEventContexts.contains(suspendContext));
+    }
+
+    myPausedContexts.addFirst(suspendContext);
+  }
+
+  public boolean hasEventContext(SuspendContextImpl suspendContext) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    return myEventContexts.contains(suspendContext);
+  }
+
+  public List<SuspendContextImpl> getEventContexts() {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    return Collections.unmodifiableList(myEventContexts);
+  }
+
+  public boolean isFrozen(ThreadReferenceProxyImpl thread) {
+    return myFrozenThreads.contains(thread);
+  }
+
+  public boolean isSuspended(ThreadReferenceProxyImpl thread) throws ObjectCollectedException{
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+
+    boolean suspended = false;
+
+    if (isFrozen(thread)) {
+      suspended = true;
+    }
+    else {
+      for (SuspendContextImpl suspendContext : myEventContexts) {
+        if (suspendContext.suspends(thread)) {
+          suspended = true;
+          break;
+        }
+      }
+    }
+
+    //bug in JDI : newly created thread may be resumed even when suspendPolicy == SUSPEND_ALL
+    //if(LOG.isDebugEnabled() && suspended) {
+    //  LOG.assertTrue(thread.suspends(), thread.name());
+    //}
+    return suspended && (thread == null || thread.isSuspended());
+  }
+
+  public void suspendThread(SuspendContextImpl context, ThreadReferenceProxyImpl thread) {
+    LOG.assertTrue(thread != context.getThread(), "Thread is already suspended at the breakpoint");
+
+    if(context.isExplicitlyResumed(thread)) {
+      context.myResumedThreads.remove(thread);
+      thread.suspend();
+    }
+  }
+
+  public void resumeThread(SuspendContextImpl context, ThreadReferenceProxyImpl thread) {
+    LOG.assertTrue(thread != context.getThread(), "Use resume() instead of resuming breakpoint thread");
+    LOG.assertTrue(!context.isExplicitlyResumed(thread));
+
+    if(context.myResumedThreads == null) {
+      context.myResumedThreads = new HashSet<ThreadReferenceProxyImpl>();
+    }
+    context.myResumedThreads.add(thread);
+    thread.resume();
+  }
+
+  public void freezeThread(ThreadReferenceProxyImpl thread) {
+    if (myFrozenThreads.add(thread)) {
+      thread.suspend();
+    }
+  }
+
+  public void unfreezeThread(ThreadReferenceProxyImpl thread) {
+    if (myFrozenThreads.remove(thread)) {
+      thread.resume();
+    }
+  }
+
+  private void processVote(SuspendContextImpl suspendContext) {
+    LOG.assertTrue(suspendContext.myVotesToVote > 0);
+    suspendContext.myVotesToVote--;
+
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("myVotesToVote = " +  suspendContext.myVotesToVote);
+    }
+    if(suspendContext.myVotesToVote == 0) {
+      if(suspendContext.myIsVotedForResume) {
+        resume(suspendContext);
+      }
+      else {
+        if (LOG.isDebugEnabled()) {
+          LOG.debug("vote paused");
+        }
+        myDebugProcess.logThreads();
+        myDebugProcess.cancelRunToCursorBreakpoint();
+        final ThreadReferenceProxyImpl thread = suspendContext.getThread();
+        myDebugProcess.deleteStepRequests(thread != null? thread.getThreadReference() : null);
+        notifyPaused(suspendContext);
+      }
+    }
+  }
+
+  public void notifyPaused(SuspendContextImpl suspendContext) {
+    pushPausedContext(suspendContext);
+    myDebugProcess.myDebugProcessDispatcher.getMulticaster().paused(suspendContext);
+  }
+
+  public void voteResume(SuspendContextImpl suspendContext) {
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("Resume voted");
+    }
+    processVote(suspendContext);
+  }
+
+  public void voteSuspend(SuspendContextImpl suspendContext) {
+    suspendContext.myIsVotedForResume = false;
+    processVote(suspendContext);
+  }
+
+  LinkedList<SuspendContextImpl> getPausedContexts() {
+    return myPausedContexts;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/SuspendManagerUtil.java b/java/debugger/impl/src/com/intellij/debugger/engine/SuspendManagerUtil.java
new file mode 100644
index 0000000..e53f9d5
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/SuspendManagerUtil.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine;
+
+import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
+import com.intellij.openapi.diagnostic.Logger;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.ListIterator;
+import java.util.Set;
+
+public class SuspendManagerUtil {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.SuspendManagerUtil");
+
+  public static boolean isEvaluating(SuspendManager suspendManager, ThreadReferenceProxyImpl thread) {
+    for (SuspendContextImpl suspendContext : suspendManager.getEventContexts()) {
+      if (suspendContext.isEvaluating() && thread.equals(suspendContext.getThread())) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  public static SuspendContextImpl findContextByThread(SuspendManager suspendManager, ThreadReferenceProxyImpl thread) {
+    for (ListIterator<SuspendContextImpl> iterator = ((SuspendManagerImpl) suspendManager).getPausedContexts().listIterator(); iterator.hasNext();) {
+      SuspendContextImpl context = iterator.next();
+      if(context.getThread() == thread) {
+        return context;
+      }
+    }
+
+    return null;
+  }
+
+  public static void assertSuspendContext(SuspendContextImpl context) {
+    if(LOG.isDebugEnabled()) {
+      LOG.assertTrue(context.myInProgress, "You can invoke methods only inside commands invoked for SuspendContext");
+    }
+  }
+
+  public static Set<SuspendContextImpl> getSuspendingContexts(SuspendManager suspendManager, ThreadReferenceProxyImpl thread) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    final Set<SuspendContextImpl> result = new HashSet<SuspendContextImpl>();
+    for (final SuspendContextImpl suspendContext : suspendManager.getEventContexts()) {
+      if (suspendContext.suspends(thread)) {
+        result.add(suspendContext);
+      }
+    }
+    return result;
+  }
+
+  public static void restoreAfterResume(SuspendContextImpl context, Object resumeData) {
+    SuspendManager suspendManager = context.getDebugProcess().getSuspendManager();
+    ResumeData data = (ResumeData) resumeData;
+
+    ThreadReferenceProxyImpl thread = context.getThread();
+    if(data.myIsFrozen && !suspendManager.isFrozen(thread)) {
+      suspendManager.freezeThread(thread);
+    }
+
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("RestoreAfterResume SuspendContextImpl...");
+    }
+    LOG.assertTrue(context.myResumedThreads == null);
+
+    if(data.myResumedThreads != null) {
+      for (Iterator<ThreadReferenceProxyImpl> iterator = data.myResumedThreads.iterator(); iterator.hasNext();) {
+        ThreadReferenceProxyImpl resumedThreads = iterator.next();
+        resumedThreads.resume();
+      }
+      context.myResumedThreads = data.myResumedThreads;
+    }
+  }
+
+  public static Object prepareForResume(SuspendContextImpl context) {
+    SuspendManager suspendManager = context.getDebugProcess().getSuspendManager();
+
+    ThreadReferenceProxyImpl thread = context.getThread();
+
+    ResumeData resumeData = new ResumeData(suspendManager.isFrozen(thread), context.myResumedThreads);
+
+    if(resumeData.myIsFrozen) {
+      suspendManager.unfreezeThread(thread);
+    }
+
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("Resuming SuspendContextImpl...");
+    }
+    if(context.myResumedThreads != null) {
+      for (Iterator<ThreadReferenceProxyImpl> iterator = context.myResumedThreads.iterator(); iterator.hasNext();) {
+        ThreadReferenceProxyImpl resumedThreads = iterator.next();
+        resumedThreads.suspend();
+      }
+      context.myResumedThreads = null;
+    }
+
+    return resumeData;
+  }
+
+  public static SuspendContextImpl getSuspendContextForThread(SuspendContextImpl suspendContext, ThreadReferenceProxyImpl thread) {
+    if (suspendContext == null) {
+      return null;
+    }
+    SuspendContextImpl context = findContextByThread(suspendContext.getDebugProcess().getSuspendManager(), thread);
+    return context != null && !context.myInProgress ? context :  suspendContext;
+  }
+
+  public static SuspendContextImpl getEvaluatingContext(SuspendManager suspendManager, ThreadReferenceProxyImpl thread) {
+    for (SuspendContextImpl suspendContext : suspendManager.getEventContexts()) {
+      if (!suspendContext.isResumed() && suspendContext.isEvaluating() && suspendContext.getThread() == thread) {
+        return suspendContext;
+      }
+    }
+    return null;
+  }
+
+  private static class ResumeData {
+    final boolean myIsFrozen;
+    final Set<ThreadReferenceProxyImpl> myResumedThreads;
+
+    public ResumeData(boolean isFrozen, Set<ThreadReferenceProxyImpl> resumedThreads) {
+      myIsFrozen = isFrozen;
+      myResumedThreads = resumedThreads;
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/VMEventListener.java b/java/debugger/impl/src/com/intellij/debugger/engine/VMEventListener.java
new file mode 100644
index 0000000..9f6ad28
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/VMEventListener.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: lex
+ * Date: Jul 15, 2003
+ * Time: 6:38:23 PM
+ * To change this template use Options | File Templates.
+ */
+public interface VMEventListener {
+  //aware! called in DebuggerEventThread
+  void vmEvent(com.sun.jdi.event.Event event);
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/CodeFragmentFactoryContextWrapper.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/CodeFragmentFactoryContextWrapper.java
new file mode 100644
index 0000000..4249138
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/CodeFragmentFactoryContextWrapper.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2000-2010 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.debugger.engine.evaluation;
+
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilder;
+import com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilderImpl;
+import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl;
+import com.intellij.xdebugger.impl.ui.tree.ValueMarkup;
+import com.intellij.openapi.fileTypes.LanguageFileType;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Key;
+import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.JavaCodeFragment;
+import com.intellij.psi.JavaRecursiveElementVisitor;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiLocalVariable;
+import com.intellij.util.StringBuilderSpinAllocator;
+import com.sun.jdi.ObjectCollectedException;
+import com.sun.jdi.ObjectReference;
+import com.sun.jdi.Value;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: Aug 30, 2010
+ */
+public class CodeFragmentFactoryContextWrapper extends CodeFragmentFactory {
+  public static final Key<Value> LABEL_VARIABLE_VALUE_KEY = Key.create("_label_variable_value_key_");
+  public static final String DEBUG_LABEL_SUFFIX = "_DebugLabel";
+
+  private final CodeFragmentFactory myDelegate;
+
+  public CodeFragmentFactoryContextWrapper(CodeFragmentFactory delegate) {
+    myDelegate = delegate;
+  }
+
+  public JavaCodeFragment createCodeFragment(TextWithImports item, PsiElement context, Project project) {
+    return myDelegate.createCodeFragment(item, wrapContext(project, context), project);
+  }
+
+  public JavaCodeFragment createPresentationCodeFragment(TextWithImports item, PsiElement context, Project project) {
+    return myDelegate.createPresentationCodeFragment(item, wrapContext(project, context), project);
+  }
+
+  public boolean isContextAccepted(PsiElement contextElement) {
+    return myDelegate.isContextAccepted(contextElement);
+  }
+
+  public LanguageFileType getFileType() {
+    return myDelegate.getFileType();
+  }
+
+  @Override
+  public EvaluatorBuilder getEvaluatorBuilder() {
+    return myDelegate.getEvaluatorBuilder();
+  }
+  
+  private PsiElement wrapContext(Project project, final PsiElement originalContext) {
+    if (project.isDefault()) return originalContext;
+    PsiElement context = originalContext;
+    final DebugProcessImpl process = DebuggerManagerEx.getInstanceEx(project).getContext().getDebugProcess();
+    if (process != null) {
+      final Map<ObjectReference, ValueMarkup> markupMap = ValueDescriptorImpl.getMarkupMap(process);
+      if (markupMap != null && markupMap.size() > 0) {
+        final Pair<String, Map<String, ObjectReference>> markupVariables = createMarkupVariablesText(markupMap);
+        int offset = markupVariables.getFirst().length() - 1;
+        final TextWithImportsImpl textWithImports = new TextWithImportsImpl(CodeFragmentKind.CODE_BLOCK, markupVariables.getFirst(), "", myDelegate.getFileType());
+        final JavaCodeFragment codeFragment = myDelegate.createCodeFragment(textWithImports, context, project);
+        codeFragment.accept(new JavaRecursiveElementVisitor() {
+          public void visitLocalVariable(PsiLocalVariable variable) {
+            final String name = variable.getName();
+            variable.putUserData(LABEL_VARIABLE_VALUE_KEY, markupVariables.getSecond().get(name));
+          }
+        });
+        final PsiElement newContext = codeFragment.findElementAt(offset);
+        if (newContext != null) {
+          context = newContext;
+        }
+      }
+    }
+    return context;
+  }
+  
+  private static Pair<String, Map<String, ObjectReference>> createMarkupVariablesText(Map<ObjectReference, ValueMarkup> markupMap) {
+    final Map<String, ObjectReference> reverseMap = new HashMap<String, ObjectReference>();
+    final StringBuilder buffer = StringBuilderSpinAllocator.alloc();
+    try {
+      for (Iterator<Map.Entry<ObjectReference, ValueMarkup>> it = markupMap.entrySet().iterator(); it.hasNext();) {
+        Map.Entry<ObjectReference, ValueMarkup> entry = it.next();
+        final ObjectReference objectRef = entry.getKey();
+        final ValueMarkup markup = entry.getValue();
+        String labelName = markup.getText();
+        if (!StringUtil.isJavaIdentifier(labelName)) {
+          continue;
+        }
+        try {
+          final String typeName = objectRef.type().name();
+          labelName += DEBUG_LABEL_SUFFIX;
+          if (buffer.length() > 0) {
+            buffer.append("\n");
+          }
+          buffer.append(typeName).append(" ").append(labelName).append(";");
+          reverseMap.put(labelName, objectRef);
+        }
+        catch (ObjectCollectedException e) {
+          it.remove();
+        }
+      }
+      buffer.append(" ");
+      return new Pair<String, Map<String, ObjectReference>>(buffer.toString(), reverseMap);
+    }
+    finally {
+      StringBuilderSpinAllocator.dispose(buffer);
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/DebuggerHighlightFilter.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/DebuggerHighlightFilter.java
new file mode 100644
index 0000000..985b3ed
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/DebuggerHighlightFilter.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.evaluation;
+
+import com.intellij.codeInsight.daemon.impl.HighlightInfo;
+import com.intellij.codeInsight.daemon.impl.HighlightInfoFilter;
+import com.intellij.codeInsight.daemon.impl.HighlightInfoType;
+import com.intellij.debugger.ui.DebuggerExpressionComboBox;
+import com.intellij.psi.PsiFile;
+import org.jetbrains.annotations.NotNull;
+
+public class DebuggerHighlightFilter implements HighlightInfoFilter {
+  public boolean accept(@NotNull HighlightInfo highlightInfo, PsiFile file) {
+    return highlightInfo.type != HighlightInfoType.UNHANDLED_EXCEPTION ||
+           file == null ||
+           file.getUserData(DebuggerExpressionComboBox.KEY) == null;
+  }
+}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/DefaultCodeFragmentFactory.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/DefaultCodeFragmentFactory.java
new file mode 100644
index 0000000..15ff6b9
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/DefaultCodeFragmentFactory.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.evaluation;
+
+import com.intellij.codeInsight.completion.CompletionParameters;
+import com.intellij.codeInsight.completion.CompletionService;
+import com.intellij.codeInsight.completion.JavaCompletionUtil;
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.codeinsight.RuntimeTypeEvaluator;
+import com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilder;
+import com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilderImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.debugger.ui.DebuggerExpressionComboBox;
+import com.intellij.openapi.fileTypes.LanguageFileType;
+import com.intellij.openapi.fileTypes.StdFileTypes;
+import com.intellij.openapi.progress.ProgressManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.*;
+import com.intellij.util.PairFunction;
+import com.intellij.util.concurrency.Semaphore;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: Jun 7, 2005
+ */
+public class DefaultCodeFragmentFactory extends CodeFragmentFactory {
+  private static final class SingletonHolder {
+    public static final DefaultCodeFragmentFactory ourInstance = new DefaultCodeFragmentFactory();
+  }
+
+  public static DefaultCodeFragmentFactory getInstance() {
+    return SingletonHolder.ourInstance;
+  }
+
+  public JavaCodeFragment createPresentationCodeFragment(final TextWithImports item, final PsiElement context, final Project project) {
+    return createCodeFragment(item, context, project);
+  }
+
+  public JavaCodeFragment createCodeFragment(TextWithImports item, PsiElement context, final Project project) {
+    final JavaCodeFragmentFactory factory = JavaCodeFragmentFactory.getInstance(project);
+    final String text = item.getText();
+
+    final JavaCodeFragment fragment;
+    if (CodeFragmentKind.EXPRESSION == item.getKind()) {
+      final String expressionText = StringUtil.endsWithChar(text, ';')? text.substring(0, text.length() - 1) : text;
+      fragment = factory.createExpressionCodeFragment(expressionText, context, null, true);
+    }
+    else /*if (CodeFragmentKind.CODE_BLOCK == item.getKind())*/ {
+      fragment = factory.createCodeBlockCodeFragment(text, context, true);
+    }
+
+    if(item.getImports().length() > 0) {
+      fragment.addImportsFromString(item.getImports());
+    }
+    fragment.setVisibilityChecker(JavaCodeFragment.VisibilityChecker.EVERYTHING_VISIBLE);
+    //noinspection HardCodedStringLiteral
+    fragment.putUserData(DebuggerExpressionComboBox.KEY, "DebuggerComboBoxEditor.IS_DEBUGGER_EDITOR");
+    fragment.putCopyableUserData(JavaCompletionUtil.DYNAMIC_TYPE_EVALUATOR, new PairFunction<PsiExpression, CompletionParameters, PsiType>() {
+      public PsiType fun(PsiExpression expression, CompletionParameters parameters) {
+        if (!RuntimeTypeEvaluator.isSubtypeable(expression)) {
+          return null;
+        }
+
+        if (parameters.getInvocationCount() <= 1 && JavaCompletionUtil.mayHaveSideEffects(expression)) {
+          final CompletionService service = CompletionService.getCompletionService();
+          if (parameters.getInvocationCount() < 2) {
+            service.setAdvertisementText("Invoke completion once more to see runtime type variants");
+          }
+          return null;
+        }
+
+        final DebuggerContextImpl debuggerContext = DebuggerManagerEx.getInstanceEx(project).getContext();
+        DebuggerSession debuggerSession = debuggerContext.getDebuggerSession();
+        if (debuggerSession != null) {
+          final Semaphore semaphore = new Semaphore();
+          semaphore.down();
+          final AtomicReference<PsiClass> nameRef = new AtomicReference<PsiClass>();
+          final RuntimeTypeEvaluator worker =
+            new RuntimeTypeEvaluator(null, expression, debuggerContext, ProgressManager.getInstance().getProgressIndicator()) {
+              @Override
+              protected void typeCalculationFinished(@Nullable PsiClass type) {
+                nameRef.set(type);
+                semaphore.up();
+              }
+            };
+          debuggerContext.getDebugProcess().getManagerThread().invoke(worker);
+          for (int i = 0; i < 50; i++) {
+            ProgressManager.checkCanceled();
+            if (semaphore.waitFor(20)) break;
+          }
+          final PsiClass psiClass = nameRef.get();
+          if (psiClass != null) {
+            return JavaPsiFacade.getElementFactory(project).createType(psiClass);
+          }
+        }
+        return null;
+      }
+    });
+
+    return fragment;
+  }
+
+  public boolean isContextAccepted(PsiElement contextElement) {
+    return true; // default factory works everywhere debugger can stop
+  }
+
+  public LanguageFileType getFileType() {
+    return StdFileTypes.JAVA;
+  }
+
+  @Override
+  public EvaluatorBuilder getEvaluatorBuilder() {
+    return EvaluatorBuilderImpl.getInstance();
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/EvaluateRuntimeException.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/EvaluateRuntimeException.java
new file mode 100644
index 0000000..a5b460c
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/EvaluateRuntimeException.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.evaluation;
+
+/**
+ * @author lex
+ */
+public class EvaluateRuntimeException extends RuntimeException {
+  public EvaluateRuntimeException(EvaluateException e) {
+    super(e);
+  }
+
+  public EvaluateException getCause() {
+    return (EvaluateException)super.getCause();
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/EvaluationContextImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/EvaluationContextImpl.java
new file mode 100644
index 0000000..24babfd
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/EvaluationContextImpl.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.evaluation;
+
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
+import com.intellij.debugger.engine.SuspendContextImpl;
+import com.intellij.debugger.jdi.StackFrameProxyImpl;
+import com.intellij.openapi.project.Project;
+import com.sun.jdi.ClassLoaderReference;
+import com.sun.jdi.Value;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * User: lex
+ * Date: Aug 28, 2003
+ * Time: 2:02:29 PM
+ */
+public final class EvaluationContextImpl implements EvaluationContext{
+  private final Value myThisObject;
+  private final SuspendContextImpl mySuspendContext;
+  private final StackFrameProxyImpl myFrameProxy;
+  private boolean myAutoLoadClasses = true;
+  
+  public EvaluationContextImpl(@NotNull SuspendContextImpl suspendContext, StackFrameProxyImpl frameProxy, Value thisObject) {
+    myThisObject = thisObject;
+    myFrameProxy = frameProxy;
+    mySuspendContext = suspendContext;
+  }
+
+  public Value getThisObject() {
+    return myThisObject;
+  }
+
+  public SuspendContextImpl getSuspendContext() {
+    return mySuspendContext;
+  }
+
+  public StackFrameProxyImpl getFrameProxy() {
+    return myFrameProxy;
+  }
+
+  public DebugProcessImpl getDebugProcess() {
+    return getSuspendContext().getDebugProcess();
+  }
+
+  public Project getProject() {
+    DebugProcessImpl debugProcess = getDebugProcess();
+    return debugProcess != null ? debugProcess.getProject() : null;
+  }
+
+  public EvaluationContextImpl createEvaluationContext(Value value) {
+    final EvaluationContextImpl copy = new EvaluationContextImpl(getSuspendContext(), getFrameProxy(), value);
+    copy.setAutoLoadClasses(myAutoLoadClasses);
+    return copy;
+  }
+
+  public ClassLoaderReference getClassLoader() throws EvaluateException {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    return myFrameProxy != null ? myFrameProxy.getClassLoader() : null;
+  }
+
+  public boolean isAutoLoadClasses() {
+    return myAutoLoadClasses;
+  }
+
+  public void setAutoLoadClasses(final boolean autoLoadClasses) {
+    myAutoLoadClasses = autoLoadClasses;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/EvaluationListener.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/EvaluationListener.java
new file mode 100644
index 0000000..a9bfa83
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/EvaluationListener.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.evaluation;
+
+import com.intellij.debugger.engine.SuspendContextImpl;
+
+import java.util.EventListener;
+
+/**
+ * @author lex
+ */
+public interface EvaluationListener extends EventListener {
+  void evaluationStarted(SuspendContextImpl context);
+
+  void evaluationFinished(SuspendContextImpl context);
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/TextWithImportsImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/TextWithImportsImpl.java
new file mode 100644
index 0000000..4eda898
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/TextWithImportsImpl.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.evaluation;
+
+import com.intellij.debugger.ui.DebuggerEditorImpl;
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.fileTypes.FileTypeManager;
+import com.intellij.openapi.fileTypes.StdFileTypes;
+import com.intellij.openapi.util.Comparing;
+import com.intellij.openapi.util.Trinity;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.JavaCodeFragment;
+import com.intellij.psi.PsiExpression;
+import com.intellij.psi.PsiExpressionCodeFragment;
+import com.intellij.psi.PsiFile;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public final class TextWithImportsImpl implements TextWithImports{
+
+  private final CodeFragmentKind myKind;
+  private String myText;
+  private final FileType myFileType;
+  private final String myImports;
+
+  public TextWithImportsImpl (PsiExpression expression) {
+    myKind = CodeFragmentKind.EXPRESSION;
+    final String text = expression.getText();
+    PsiFile containingFile = expression.getContainingFile();
+    if(containingFile instanceof PsiExpressionCodeFragment) {
+      myText = text;
+      myImports = ((JavaCodeFragment)containingFile).importsToString();
+      myFileType = StdFileTypes.JAVA;
+    }
+    else {
+      Trinity<String, String, FileType> trinity = parseExternalForm(text);
+      myText = trinity.first;
+      myImports = trinity.second;
+      myFileType = trinity.third;
+    }
+  }
+
+  public TextWithImportsImpl (CodeFragmentKind kind, @NotNull String text, @NotNull String imports, @Nullable FileType fileType) {
+    myKind = kind;
+    myText = text;
+    myImports = imports;
+    myFileType = fileType;
+  }
+
+  public TextWithImportsImpl(CodeFragmentKind kind, @NotNull String text) {
+    myKind = kind;
+    Trinity<String, String, FileType> trinity = parseExternalForm(text);
+    myText = trinity.first;
+    myImports = trinity.second;
+    myFileType = trinity.third;
+  }
+
+  private static Trinity<String, String, FileType> parseExternalForm(String s) {
+    String[] split = s.split(String.valueOf(DebuggerEditorImpl.SEPARATOR));
+    return Trinity.create(split[0], split.length > 1 ? split[1] : "", split.length > 2 ? FileTypeManager.getInstance().getStdFileType(split[2]) : null);
+  }
+
+  public CodeFragmentKind getKind() {
+    return myKind;
+  }
+
+  public String getText() {
+    return myText;
+  }
+
+  public @NotNull String getImports() {
+    return myImports;
+  }
+
+  public boolean equals(Object object) {
+    if(!(object instanceof TextWithImportsImpl)) {
+      return false;
+    }
+    TextWithImportsImpl item = ((TextWithImportsImpl)object);
+    return Comparing.equal(item.myText, myText) && Comparing.equal(item.myImports, myImports);
+  }
+
+  public String toString() {
+    return getText();
+  }
+
+  public String toExternalForm() {
+    String result = myText;
+    if (StringUtil.isNotEmpty(myImports) || myFileType != null) {
+      result += DebuggerEditorImpl.SEPARATOR + myImports;
+    }
+    if (myFileType != null) {
+      result += DebuggerEditorImpl.SEPARATOR + myFileType.getName();
+    }
+    return result;
+  }
+
+  public int hashCode() {
+    return myText.hashCode();
+  }
+
+  public boolean isEmpty() {
+    final String text = getText();
+    return text == null || "".equals(text.trim());
+  }
+
+  public void setText(String newText) {
+    myText = newText;
+  }
+
+  public FileType getFileType() {
+    return myFileType;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ArrayAccessEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ArrayAccessEvaluator.java
new file mode 100644
index 0000000..4413c83
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ArrayAccessEvaluator.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class ArrayAccessEvaluator
+ * @author Jeka
+ */
+package com.intellij.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl;
+import com.intellij.debugger.ui.impl.watch.ArrayElementDescriptorImpl;
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.openapi.project.Project;
+import com.sun.jdi.*;
+
+class ArrayAccessEvaluator implements Evaluator {
+  private final Evaluator myArrayReferenceEvaluator;
+  private final Evaluator myIndexEvaluator;
+  private ArrayReference myEvaluatedArrayReference;
+  private int myEvaluatedIndex;
+
+  public ArrayAccessEvaluator(Evaluator arrayReferenceEvaluator, Evaluator indexEvaluator) {
+    myArrayReferenceEvaluator = arrayReferenceEvaluator;
+    myIndexEvaluator = indexEvaluator;
+  }
+
+  public Object evaluate(EvaluationContextImpl context) throws EvaluateException {
+    myEvaluatedIndex = 0;
+    myEvaluatedArrayReference = null;
+    Value indexValue = (Value)myIndexEvaluator.evaluate(context);
+    Value arrayValue = (Value)myArrayReferenceEvaluator.evaluate(context);
+    if (!(arrayValue instanceof ArrayReference)) {
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.array.reference.expected"));
+    }
+    myEvaluatedArrayReference = (ArrayReference)arrayValue;
+    if (!DebuggerUtilsEx.isInteger(indexValue)) {
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.invalid.index.expression"));
+    }
+    myEvaluatedIndex = ((PrimitiveValue)indexValue).intValue();
+    try {
+      return myEvaluatedArrayReference.getValue(myEvaluatedIndex);
+    }
+    catch (Exception e) {
+      throw EvaluateExceptionUtil.createEvaluateException(e);
+    }
+  }
+
+  public Modifier getModifier() {
+    Modifier modifier = null;
+    if (myEvaluatedArrayReference != null) {
+      modifier = new Modifier() {
+        public boolean canInspect() {
+          return true;
+        }
+
+        public boolean canSetValue() {
+          return true;
+        }
+
+        public void setValue(Value value) throws ClassNotLoadedException, InvalidTypeException {
+          myEvaluatedArrayReference.setValue(myEvaluatedIndex, value);
+        }
+
+        public Type getExpectedType() throws EvaluateException {
+          try {
+            ArrayType type = (ArrayType)myEvaluatedArrayReference.referenceType();
+            return type.componentType();
+          }
+          catch (ClassNotLoadedException e) {
+            throw EvaluateExceptionUtil.createEvaluateException(e);
+          }
+        }
+
+        public NodeDescriptorImpl getInspectItem(Project project) {
+          return new ArrayElementDescriptorImpl(project, myEvaluatedArrayReference, myEvaluatedIndex);
+        }
+      };
+    }
+    return modifier;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ArrayInitializerEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ArrayInitializerEvaluator.java
new file mode 100644
index 0000000..0fe3395
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ArrayInitializerEvaluator.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/**
+ * class ArrayInitializerEvaluator
+ * created Jun 28, 2001
+ * @author Jeka
+ */
+package com.intellij.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+
+class ArrayInitializerEvaluator implements Evaluator{
+  private final Evaluator[] myValueEvaluators;
+
+  public ArrayInitializerEvaluator(Evaluator[] valueEvaluators) {
+    myValueEvaluators = valueEvaluators;
+  }
+
+  /**
+   * @return an array of Values
+   */
+  public Object evaluate(EvaluationContextImpl context) throws EvaluateException {
+    Object[] values = new Object[myValueEvaluators.length];
+    for (int idx = 0; idx < myValueEvaluators.length; idx++) {
+      Evaluator evaluator = myValueEvaluators[idx];
+      values[idx] = evaluator.evaluate(context);
+    }
+    return values;
+  }
+
+  public Modifier getModifier() {
+    return null;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/AssignmentEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/AssignmentEvaluator.java
new file mode 100644
index 0000000..8a2f199
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/AssignmentEvaluator.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.sun.jdi.*;
+
+/**
+ * @author lex
+ */
+public class AssignmentEvaluator implements Evaluator{
+  private final Evaluator myLeftEvaluator;
+  private final Evaluator myRightEvaluator;
+
+  public AssignmentEvaluator(Evaluator leftEvaluator, Evaluator rightEvaluator) {
+    myLeftEvaluator = leftEvaluator;
+    myRightEvaluator = new DisableGC(rightEvaluator);
+  }
+
+  public Object evaluate(EvaluationContextImpl context) throws EvaluateException {
+    Object right = myRightEvaluator.evaluate(context);
+    if(right != null && !(right instanceof Value)) {
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.not.rvalue"));
+    }
+
+    myLeftEvaluator.evaluate(context);
+    Modifier modifier = myLeftEvaluator.getModifier();
+    assign(modifier, right, context);
+    return right;
+  }
+
+  static void assign(Modifier modifier, Object right, EvaluationContextImpl context) throws EvaluateException {
+    if(modifier == null) {
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.not.lvalue"));
+    }
+    try {
+      modifier.setValue(((Value)right));
+    }
+    catch (ClassNotLoadedException e) {
+      if (!context.isAutoLoadClasses()) {
+        throw EvaluateExceptionUtil.createEvaluateException(e);
+      }
+      try {
+        context.getDebugProcess().loadClass(context, e.className(), context.getClassLoader());
+      }
+      catch (InvocationException e1) {
+        throw EvaluateExceptionUtil.createEvaluateException(e1);
+      }
+      catch (ClassNotLoadedException e1) {
+        throw EvaluateExceptionUtil.createEvaluateException(e1);
+      }
+      catch (IncompatibleThreadStateException e1) {
+        throw EvaluateExceptionUtil.createEvaluateException(e1);
+      }
+      catch (InvalidTypeException e1) {
+        throw EvaluateExceptionUtil.createEvaluateException(e1);
+      }
+    }
+    catch (InvalidTypeException e) {
+      throw EvaluateExceptionUtil.createEvaluateException(e);
+    }
+  }
+
+  public Modifier getModifier() {
+    return myLeftEvaluator.getModifier();
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/BinaryExpressionEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/BinaryExpressionEvaluator.java
new file mode 100644
index 0000000..db00e47
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/BinaryExpressionEvaluator.java
@@ -0,0 +1,443 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class BinaryExpressionEvaluator
+ * @author Jeka
+ */
+package com.intellij.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.psi.JavaTokenType;
+import com.intellij.psi.tree.IElementType;
+import com.sun.jdi.*;
+
+class BinaryExpressionEvaluator implements Evaluator {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.evaluation.expression.BinaryExpressionEvaluator");
+  private final Evaluator myLeftOperand;
+  private final Evaluator myRightOperand;
+  private final IElementType myOpType;
+  private final String myExpectedType; // a result of PsiType.getCanonicalText()
+
+  public BinaryExpressionEvaluator(Evaluator leftOperand, Evaluator rightOperand, IElementType opType, String expectedType) {
+    myLeftOperand = new DisableGC(leftOperand);
+    myRightOperand = new DisableGC(rightOperand);
+    myOpType = opType;
+    myExpectedType = expectedType;
+  }
+
+  public Modifier getModifier() {
+    return null;
+  }
+
+  public Object evaluate(EvaluationContextImpl context) throws EvaluateException {
+    Value leftResult = (Value)myLeftOperand.evaluate(context);
+    return evaluateOperation(leftResult, myOpType, myRightOperand, myExpectedType, context);
+
+  }
+
+  static Object evaluateOperation(final Value leftResult,
+                                  final IElementType opType,
+                                  final Evaluator rightOperand,
+                                  final String expectedType,
+                                  final EvaluationContextImpl context) throws EvaluateException {
+    VirtualMachineProxyImpl vm = context.getDebugProcess().getVirtualMachineProxy();
+    if (leftResult instanceof BooleanValue) {
+      boolean v1 = ((PrimitiveValue)leftResult).booleanValue();
+      if (opType == JavaTokenType.OROR && v1) {
+        return DebuggerUtilsEx.createValue(vm, expectedType, true);
+      }
+      if (opType == JavaTokenType.ANDAND && !v1) {
+        return DebuggerUtilsEx.createValue(vm, expectedType, false);
+      }
+    }
+    Value rightResult = (Value)rightOperand.evaluate(context);
+    if (opType == JavaTokenType.PLUS) {
+      if (DebuggerUtilsEx.isInteger(leftResult) && DebuggerUtilsEx.isInteger(rightResult)) {
+        final long v1 = ((PrimitiveValue)leftResult).longValue();
+        final long v2 = ((PrimitiveValue)rightResult).longValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 + v2);
+      }
+      if (DebuggerUtilsEx.isNumeric(leftResult) && DebuggerUtilsEx.isNumeric(rightResult)) {
+        final double v1 = ((PrimitiveValue)leftResult).doubleValue();
+        final double v2 = ((PrimitiveValue)rightResult).doubleValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 + v2);
+      }
+      if (leftResult instanceof CharValue && rightResult instanceof CharValue) {
+        char v1 = ((CharValue)leftResult).charValue();
+        char v2 = ((CharValue)rightResult).charValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 + v2);
+      }
+      if (leftResult instanceof StringReference || rightResult instanceof StringReference) {
+        String v1 = DebuggerUtilsEx.getValueAsString(context, leftResult);
+        String v2 = DebuggerUtilsEx.getValueAsString(context, rightResult);
+        return vm.mirrorOf(v1 + v2);
+      }
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.incompatible.types", "+"));
+    }
+    else if (opType == JavaTokenType.MINUS) {
+      if (DebuggerUtilsEx.isInteger(leftResult) && DebuggerUtilsEx.isInteger(rightResult)) {
+        final long v1 = ((PrimitiveValue)leftResult).longValue();
+        final long v2 = ((PrimitiveValue)rightResult).longValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 - v2);
+      }
+      if (DebuggerUtilsEx.isNumeric(leftResult) && DebuggerUtilsEx.isNumeric(rightResult)) {
+        double v1 = ((PrimitiveValue)leftResult).doubleValue();
+        double v2 = ((PrimitiveValue)rightResult).doubleValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 - v2);
+      }
+      if (leftResult instanceof CharValue && rightResult instanceof CharValue) {
+        char v1 = ((CharValue)leftResult).charValue();
+        char v2 = ((CharValue)rightResult).charValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 - v2);
+      }
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.incompatible.types", "-"));
+    }
+    else if (opType == JavaTokenType.ASTERISK) {
+      if (DebuggerUtilsEx.isInteger(leftResult) && DebuggerUtilsEx.isInteger(rightResult)) {
+        final long v1 = ((PrimitiveValue)leftResult).longValue();
+        final long v2 = ((PrimitiveValue)rightResult).longValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 * v2);
+      }
+      if (DebuggerUtilsEx.isNumeric(leftResult) && DebuggerUtilsEx.isNumeric(rightResult)) {
+        double v1 = ((PrimitiveValue)leftResult).doubleValue();
+        double v2 = ((PrimitiveValue)rightResult).doubleValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 * v2);
+      }
+      if (leftResult instanceof CharValue && rightResult instanceof CharValue) {
+        char v1 = ((CharValue)leftResult).charValue();
+        char v2 = ((CharValue)rightResult).charValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 * v2);
+      }
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.incompatible.types", "*"));
+    }
+    else if (opType == JavaTokenType.DIV) {
+      if (DebuggerUtilsEx.isInteger(leftResult) && DebuggerUtilsEx.isInteger(rightResult)) {
+        long v1 = ((PrimitiveValue)leftResult).longValue();
+        long v2 = ((PrimitiveValue)rightResult).longValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 / v2);
+      }
+      if (DebuggerUtilsEx.isNumeric(leftResult) && DebuggerUtilsEx.isNumeric(rightResult)) {
+        double v1 = ((PrimitiveValue)leftResult).doubleValue();
+        double v2 = ((PrimitiveValue)rightResult).doubleValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 / v2);
+      }
+      if (leftResult instanceof CharValue && rightResult instanceof CharValue) {
+        char v1 = ((CharValue)leftResult).charValue();
+        char v2 = ((CharValue)rightResult).charValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 / v2);
+      }
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.incompatible.types", "/"));
+    }
+    else if (opType == JavaTokenType.PERC) {
+      if (DebuggerUtilsEx.isInteger(leftResult) && DebuggerUtilsEx.isInteger(rightResult)) {
+        long v1 = ((PrimitiveValue)leftResult).longValue();
+        long v2 = ((PrimitiveValue)rightResult).longValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 % v2);
+      }
+      if (DebuggerUtilsEx.isNumeric(leftResult) && DebuggerUtilsEx.isNumeric(rightResult)) {
+        double v1 = ((PrimitiveValue)leftResult).doubleValue();
+        double v2 = ((PrimitiveValue)rightResult).doubleValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 % v2);
+      }
+      if (leftResult instanceof CharValue && rightResult instanceof CharValue) {
+        char v1 = ((CharValue)leftResult).charValue();
+        char v2 = ((CharValue)rightResult).charValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 % v2);
+      }
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.incompatible.types", "%"));
+    }
+    else if (opType == JavaTokenType.LTLT) {
+      if (DebuggerUtilsEx.isInteger(leftResult) && DebuggerUtilsEx.isInteger(rightResult)) {
+        final long v2 = ((PrimitiveValue)rightResult).longValue();
+        if (leftResult instanceof ByteValue) {
+          return DebuggerUtilsEx.createValue(vm, expectedType, ((ByteValue)leftResult).byteValue() << v2);
+        }
+        else if (leftResult instanceof ShortValue) {
+          return DebuggerUtilsEx.createValue(vm, expectedType, ((ShortValue)leftResult).shortValue() << v2);
+        }
+        else if (leftResult instanceof IntegerValue) {
+          return DebuggerUtilsEx.createValue(vm, expectedType, ((IntegerValue)leftResult).intValue() << v2);
+        }
+        return DebuggerUtilsEx.createValue(vm, expectedType, ((PrimitiveValue)leftResult).longValue() << v2);
+      }
+      if (leftResult instanceof CharValue && rightResult instanceof CharValue) {
+        return DebuggerUtilsEx.createValue(vm, expectedType, ((CharValue)leftResult).charValue() << ((CharValue)rightResult).charValue());
+      }
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.incompatible.types", "<<"));
+    }
+    else if (opType == JavaTokenType.GTGT) {
+      if (DebuggerUtilsEx.isInteger(leftResult) && DebuggerUtilsEx.isInteger(rightResult)) {
+        final long v2 = ((PrimitiveValue)rightResult).longValue();
+        if (leftResult instanceof ByteValue) {
+          return DebuggerUtilsEx.createValue(vm, expectedType, ((ByteValue)leftResult).byteValue() >> v2);
+        }
+        else if (leftResult instanceof ShortValue) {
+          return DebuggerUtilsEx.createValue(vm, expectedType, ((ShortValue)leftResult).shortValue() >> v2);
+        }
+        else if (leftResult instanceof IntegerValue) {
+          return DebuggerUtilsEx.createValue(vm, expectedType, ((IntegerValue)leftResult).intValue() >> v2);
+        }
+        return DebuggerUtilsEx.createValue(vm, expectedType, ((PrimitiveValue)leftResult).longValue() >> v2);
+      }
+      if (leftResult instanceof CharValue && rightResult instanceof CharValue) {
+        return DebuggerUtilsEx.createValue(vm, expectedType, ((CharValue)leftResult).charValue() >> ((CharValue)rightResult).charValue());
+      }
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.incompatible.types", ">>"));
+    }
+    else if (opType == JavaTokenType.GTGTGT) {
+      if (DebuggerUtilsEx.isInteger(leftResult) && DebuggerUtilsEx.isInteger(rightResult)) {
+        final long v2 = ((PrimitiveValue)rightResult).longValue();
+        if (leftResult instanceof ByteValue) {
+          return DebuggerUtilsEx.createValue(vm, expectedType, ((ByteValue)leftResult).byteValue() >>> v2);
+        }
+        else if (leftResult instanceof ShortValue) {
+          return DebuggerUtilsEx.createValue(vm, expectedType, ((ShortValue)leftResult).shortValue() >>> v2);
+        }
+        else if (leftResult instanceof IntegerValue) {
+          return DebuggerUtilsEx.createValue(vm, expectedType, ((IntegerValue)leftResult).intValue() >>> v2);
+        }
+        return DebuggerUtilsEx.createValue(vm, expectedType, ((PrimitiveValue)leftResult).longValue() >>> v2);
+      }
+      if (leftResult instanceof CharValue && rightResult instanceof CharValue) {
+        return DebuggerUtilsEx.createValue(vm, expectedType, ((CharValue)leftResult).charValue() >>> ((CharValue)rightResult).charValue());
+      }
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.incompatible.types", ">>>"));
+    }
+    else if (opType == JavaTokenType.AND) {
+      if (DebuggerUtilsEx.isInteger(leftResult) && DebuggerUtilsEx.isInteger(rightResult)) {
+        long v1 = ((PrimitiveValue)leftResult).longValue();
+        long v2 = ((PrimitiveValue)rightResult).longValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 & v2);
+      }
+      if (leftResult instanceof CharValue && rightResult instanceof CharValue) {
+        char v1 = ((CharValue)leftResult).charValue();
+        char v2 = ((CharValue)rightResult).charValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 & v2);
+      }
+      if (leftResult instanceof BooleanValue && rightResult instanceof BooleanValue) {
+        boolean v1 = ((PrimitiveValue)leftResult).booleanValue();
+        boolean v2 = ((PrimitiveValue)rightResult).booleanValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 & v2);
+      }
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.incompatible.types", "&"));
+    }
+    else if (opType == JavaTokenType.OR) {
+      if (DebuggerUtilsEx.isInteger(leftResult) && DebuggerUtilsEx.isInteger(rightResult)) {
+        long v1 = ((PrimitiveValue)leftResult).longValue();
+        long v2 = ((PrimitiveValue)rightResult).longValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 | v2);
+      }
+      if (leftResult instanceof CharValue && rightResult instanceof CharValue) {
+        char v1 = ((CharValue)leftResult).charValue();
+        char v2 = ((CharValue)rightResult).charValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 | v2);
+      }
+      if (leftResult instanceof BooleanValue && rightResult instanceof BooleanValue) {
+        boolean v1 = ((PrimitiveValue)leftResult).booleanValue();
+        boolean v2 = ((PrimitiveValue)rightResult).booleanValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 | v2);
+      }
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.incompatible.types", "|"));
+    }
+    else if (opType == JavaTokenType.XOR) {
+      if (DebuggerUtilsEx.isInteger(leftResult) && DebuggerUtilsEx.isInteger(rightResult)) {
+        long v1 = ((PrimitiveValue)leftResult).longValue();
+        long v2 = ((PrimitiveValue)rightResult).longValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 ^ v2);
+      }
+      if (leftResult instanceof CharValue && rightResult instanceof CharValue) {
+        char v1 = ((CharValue)leftResult).charValue();
+        char v2 = ((CharValue)rightResult).charValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 ^ v2);
+      }
+      if (leftResult instanceof BooleanValue && rightResult instanceof BooleanValue) {
+        boolean v1 = ((PrimitiveValue)leftResult).booleanValue();
+        boolean v2 = ((PrimitiveValue)rightResult).booleanValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 ^ v2);
+      }
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.incompatible.types", "^"));
+    }
+    else if (opType == JavaTokenType.EQEQ) {
+      if (leftResult == null && rightResult == null) {
+        return DebuggerUtilsEx.createValue(vm, expectedType, true);
+      }
+      if (leftResult == null) {
+        return DebuggerUtilsEx.createValue(vm, expectedType, rightResult.equals(leftResult));
+      }
+      if (rightResult == null) {
+        return DebuggerUtilsEx.createValue(vm, expectedType, leftResult.equals(rightResult));
+      }
+      if (DebuggerUtilsEx.isInteger(leftResult) && DebuggerUtilsEx.isInteger(rightResult)) {
+        final long v1 = ((PrimitiveValue)leftResult).longValue();
+        final long v2 = ((PrimitiveValue)rightResult).longValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 == v2);
+      }
+      if (DebuggerUtilsEx.isNumeric(leftResult) && DebuggerUtilsEx.isNumeric(rightResult)) {
+        double v1 = ((PrimitiveValue)leftResult).doubleValue();
+        double v2 = ((PrimitiveValue)rightResult).doubleValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 == v2);
+      }
+      if (leftResult instanceof BooleanValue && rightResult instanceof BooleanValue) {
+        boolean v1 = ((PrimitiveValue)leftResult).booleanValue();
+        boolean v2 = ((PrimitiveValue)rightResult).booleanValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 == v2);
+      }
+      if (leftResult instanceof CharValue && rightResult instanceof CharValue) {
+        char v1 = ((CharValue)leftResult).charValue();
+        char v2 = ((CharValue)rightResult).charValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 == v2);
+      }
+      if (leftResult instanceof ObjectReference && rightResult instanceof ObjectReference) {
+        ObjectReference v1 = (ObjectReference)leftResult;
+        ObjectReference v2 = (ObjectReference)rightResult;
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1.uniqueID() == v2.uniqueID());
+      }
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.incompatible.types", "=="));
+    }
+    else if (opType == JavaTokenType.OROR) {
+      if (leftResult instanceof BooleanValue && rightResult instanceof BooleanValue) {
+        boolean v1 = ((PrimitiveValue)leftResult).booleanValue();
+        boolean v2 = ((PrimitiveValue)rightResult).booleanValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 || v2);
+      }
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.incompatible.types", "||"));
+    }
+    else if (opType == JavaTokenType.ANDAND) {
+      if (leftResult instanceof BooleanValue && rightResult instanceof BooleanValue) {
+        boolean v1 = ((PrimitiveValue)leftResult).booleanValue();
+        boolean v2 = ((PrimitiveValue)rightResult).booleanValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 && v2);
+      }
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.incompatible.types", "&&"));
+    }
+    else if (opType == JavaTokenType.NE) {
+      if (leftResult == null && rightResult == null) return DebuggerUtilsEx.createValue(vm, expectedType, false);
+      if (leftResult == null) return DebuggerUtilsEx.createValue(vm, expectedType, !rightResult.equals(leftResult));
+      if (rightResult == null) return DebuggerUtilsEx.createValue(vm, expectedType, !leftResult.equals(rightResult));
+      if (DebuggerUtilsEx.isInteger(leftResult) && DebuggerUtilsEx.isInteger(rightResult)) {
+        final long v1 = ((PrimitiveValue)leftResult).longValue();
+        final long v2 = ((PrimitiveValue)rightResult).longValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 != v2);
+      }
+      if (DebuggerUtilsEx.isNumeric(leftResult) && DebuggerUtilsEx.isNumeric(rightResult)) {
+        double v1 = ((PrimitiveValue)leftResult).doubleValue();
+        double v2 = ((PrimitiveValue)rightResult).doubleValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 != v2);
+      }
+      if (leftResult instanceof BooleanValue && rightResult instanceof BooleanValue) {
+        boolean v1 = ((PrimitiveValue)leftResult).booleanValue();
+        boolean v2 = ((PrimitiveValue)rightResult).booleanValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 != v2);
+      }
+      if (leftResult instanceof CharValue && rightResult instanceof CharValue) {
+        char v1 = ((CharValue)leftResult).charValue();
+        char v2 = ((CharValue)rightResult).charValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 != v2);
+      }
+      if (leftResult instanceof ObjectReference && rightResult instanceof ObjectReference) {
+        ObjectReference v1 = (ObjectReference)leftResult;
+        ObjectReference v2 = (ObjectReference)rightResult;
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1.uniqueID() != v2.uniqueID());
+      }
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.incompatible.types", "!="));
+    }
+    else if (opType == JavaTokenType.LT) {
+      if (DebuggerUtilsEx.isInteger(leftResult) && DebuggerUtilsEx.isInteger(rightResult)) {
+        final long v1 = ((PrimitiveValue)leftResult).longValue();
+        final long v2 = ((PrimitiveValue)rightResult).longValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 < v2);
+      }
+      if (DebuggerUtilsEx.isNumeric(leftResult) && DebuggerUtilsEx.isNumeric(rightResult)) {
+        double v1 = ((PrimitiveValue)leftResult).doubleValue();
+        double v2 = ((PrimitiveValue)rightResult).doubleValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 < v2);
+      }
+      if (leftResult instanceof CharValue && rightResult instanceof CharValue) {
+        char v1 = ((CharValue)leftResult).charValue();
+        char v2 = ((CharValue)rightResult).charValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 < v2);
+      }
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.incompatible.types", "<"));
+    }
+    else if (opType == JavaTokenType.GT) {
+      if (DebuggerUtilsEx.isInteger(leftResult) && DebuggerUtilsEx.isInteger(rightResult)) {
+        final long v1 = ((PrimitiveValue)leftResult).longValue();
+        final long v2 = ((PrimitiveValue)rightResult).longValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 > v2);
+      }
+      if (DebuggerUtilsEx.isNumeric(leftResult) && DebuggerUtilsEx.isNumeric(rightResult)) {
+        double v1 = ((PrimitiveValue)leftResult).doubleValue();
+        double v2 = ((PrimitiveValue)rightResult).doubleValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 > v2);
+      }
+      if (leftResult instanceof CharValue && rightResult instanceof CharValue) {
+        char v1 = ((CharValue)leftResult).charValue();
+        char v2 = ((CharValue)rightResult).charValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 > v2);
+      }
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.incompatible.types", ">"));
+    }
+    else if (opType == JavaTokenType.LE) {
+      if (DebuggerUtilsEx.isInteger(leftResult) && DebuggerUtilsEx.isInteger(rightResult)) {
+        final long v1 = ((PrimitiveValue)leftResult).longValue();
+        final long v2 = ((PrimitiveValue)rightResult).longValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 <= v2);
+      }
+      if (DebuggerUtilsEx.isNumeric(leftResult) && DebuggerUtilsEx.isNumeric(rightResult)) {
+        double v1 = ((PrimitiveValue)leftResult).doubleValue();
+        double v2 = ((PrimitiveValue)rightResult).doubleValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 <= v2);
+      }
+      if (leftResult instanceof CharValue && rightResult instanceof CharValue) {
+        char v1 = ((CharValue)leftResult).charValue();
+        char v2 = ((CharValue)rightResult).charValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 <= v2);
+      }
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.incompatible.types", "<="));
+    }
+    else if (opType == JavaTokenType.GE) {
+      if (DebuggerUtilsEx.isInteger(leftResult) && DebuggerUtilsEx.isInteger(rightResult)) {
+        final long v1 = ((PrimitiveValue)leftResult).longValue();
+        final long v2 = ((PrimitiveValue)rightResult).longValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 >= v2);
+      }
+      if (DebuggerUtilsEx.isNumeric(leftResult) && DebuggerUtilsEx.isNumeric(rightResult)) {
+        double v1 = ((PrimitiveValue)leftResult).doubleValue();
+        double v2 = ((PrimitiveValue)rightResult).doubleValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 >= v2);
+      }
+      if (leftResult instanceof CharValue && rightResult instanceof CharValue) {
+        char v1 = ((CharValue)leftResult).charValue();
+        char v2 = ((CharValue)rightResult).charValue();
+        return DebuggerUtilsEx.createValue(vm, expectedType, v1 >= v2);
+      }
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.incompatible.types", ">="));
+    }
+
+    LOG.assertTrue(false);
+
+    return null;
+  }
+
+  
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/BlockStatementEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/BlockStatementEvaluator.java
new file mode 100644
index 0000000..464aa6e
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/BlockStatementEvaluator.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+
+/**
+ * @author lex
+ */
+public class BlockStatementEvaluator implements Evaluator {
+  protected Evaluator[] myStatements;
+
+  public BlockStatementEvaluator(Evaluator[] statements) {
+    myStatements = statements;
+  }
+
+  public Object evaluate(EvaluationContextImpl context) throws EvaluateException {
+    Object result = context.getSuspendContext().getDebugProcess().getVirtualMachineProxy().mirrorOf();
+    for (Evaluator statement : myStatements) {
+      result = statement.evaluate(context);
+    }
+    return result;
+  }
+
+  public Modifier getModifier() {
+    return myStatements.length > 0 ? myStatements[myStatements.length - 1].getModifier() : null;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/BoxingEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/BoxingEvaluator.java
new file mode 100644
index 0000000..2d757a3
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/BoxingEvaluator.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2000-2010 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.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.JVMNameUtil;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.sun.jdi.*;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: Feb 8, 2010
+ */
+public class BoxingEvaluator implements Evaluator{
+  private final Evaluator myOperand;
+
+  public BoxingEvaluator(Evaluator operand) {
+    myOperand = new DisableGC(operand);
+  }
+
+  public Object evaluate(EvaluationContextImpl context) throws EvaluateException {
+    final Object result = myOperand.evaluate(context);
+    if (result == null || result instanceof ObjectReference) {
+      return result;
+    }
+
+    if (result instanceof BooleanValue) {
+      return convertToWrapper(context, (BooleanValue)result, "java.lang.Boolean");
+    }
+    if (result instanceof ByteValue) {
+      return convertToWrapper(context, (ByteValue)result, "java.lang.Byte");
+    }
+    if (result instanceof CharValue) {
+      return convertToWrapper(context, (CharValue)result, "java.lang.Character");
+    }
+    if (result instanceof ShortValue) {
+      return convertToWrapper(context, (ShortValue)result, "java.lang.Short");
+    }
+    if (result instanceof IntegerValue) {
+      return convertToWrapper(context, (IntegerValue)result, "java.lang.Integer");
+    }
+    if (result instanceof LongValue) {
+      return convertToWrapper(context, (LongValue)result, "java.lang.Long");
+    }
+    if (result instanceof FloatValue) {
+      return convertToWrapper(context, (FloatValue)result, "java.lang.Float");
+    }
+    if (result instanceof DoubleValue) {
+      return convertToWrapper(context, (DoubleValue)result, "java.lang.Double");
+    }
+    throw new EvaluateException("Cannot perform boxing conversion for a value of type " + ((Value)result).type().name());
+  }
+
+  @Nullable
+  public Modifier getModifier() {
+    return null;
+  }
+
+  private static Value convertToWrapper(EvaluationContextImpl context, PrimitiveValue value, String wrapperTypeName) throws
+                                                                                                                            EvaluateException {
+    final DebugProcessImpl process = context.getDebugProcess();
+    final ClassType wrapperClass = (ClassType)process.findClass(context, wrapperTypeName, null);
+    final String methodSignature = "(" + JVMNameUtil.getPrimitiveSignature(value.type().name()) + ")L" + wrapperTypeName.replace('.', '/') + ";";
+
+    List<Method> methods = wrapperClass.methodsByName("valueOf", methodSignature);
+    if (methods.size() == 0) { // older JDK version
+      methods = wrapperClass.methodsByName("<init>", methodSignature);
+    }
+    if (methods.size() == 0) {
+      throw new EvaluateException("Cannot construct wrapper object for value of type " + value.type() + ": Unable to find either valueOf() or constructor method");
+    }
+    
+    final Method factoryMethod = methods.get(0);
+
+    final ArrayList args = new ArrayList();
+    args.add(value);
+    
+    return process.invokeMethod(context, wrapperClass, factoryMethod, args);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/BreakContinueStatementEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/BreakContinueStatementEvaluator.java
new file mode 100644
index 0000000..e65a322
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/BreakContinueStatementEvaluator.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+
+/**
+ * @author lex
+ */
+public class BreakContinueStatementEvaluator {
+  private BreakContinueStatementEvaluator() {
+  }
+
+  public static Evaluator createBreakEvaluator(final String labelName) {
+    return new Evaluator() {
+      public Object evaluate(EvaluationContextImpl context) throws BreakException {
+        throw new BreakException(labelName);
+      }
+
+      public Modifier getModifier() {
+        return null;
+      }
+    };
+  }
+
+  public static Evaluator createContinueEvaluator(final String labelName) {
+    return new Evaluator() {
+      public Object evaluate(EvaluationContextImpl context) throws ContinueException {
+        throw new ContinueException(labelName);
+      }
+
+      public Modifier getModifier() {
+        return null;
+      }
+    };
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/BreakException.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/BreakException.java
new file mode 100644
index 0000000..24a7fe5
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/BreakException.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+
+/**
+ * @author lex
+ */
+public class BreakException extends EvaluateException{
+  private final String myLabelName;
+
+  public BreakException(String labelName) {
+    super(DebuggerBundle.message("evaluation.error.lebeled.loops.not.found", labelName), null);
+    myLabelName = labelName;
+  }
+
+  public String getLabelName() {
+    return myLabelName;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ClassObjectEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ClassObjectEvaluator.java
new file mode 100644
index 0000000..d9ad11f
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ClassObjectEvaluator.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class ClassObjectEvaluator
+ * @author Jeka
+ */
+package com.intellij.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.DebuggerBundle;
+import com.sun.jdi.ReferenceType;
+
+public class ClassObjectEvaluator implements Evaluator {
+  private final TypeEvaluator myTypeEvaluator;
+
+  public ClassObjectEvaluator(TypeEvaluator typeEvaluator) {
+    myTypeEvaluator = typeEvaluator;
+  }
+
+  public Modifier getModifier() {
+    return null;
+  }
+
+  public Object evaluate(EvaluationContextImpl context) throws EvaluateException {
+    Object object = myTypeEvaluator.evaluate(context);
+    if (!(object instanceof ReferenceType)) {
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.reference.type.expected"));
+    }
+    return ((ReferenceType)object).classObject();
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/CodeFragmentEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/CodeFragmentEvaluator.java
new file mode 100644
index 0000000..6572d44
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/CodeFragmentEvaluator.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.util.containers.HashMap;
+import com.sun.jdi.Value;
+
+import java.util.Map;
+
+/**
+ * @author lex
+ */
+public class CodeFragmentEvaluator extends BlockStatementEvaluator{
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.evaluation.expression.CodeFragmentEvaluator");
+
+  private final CodeFragmentEvaluator myParentFragmentEvaluator;
+  private final Map<String, Object> mySyntheticLocals = new HashMap<String, Object>();
+
+  public CodeFragmentEvaluator(CodeFragmentEvaluator parentFragmentEvaluator) {
+    super(null);
+    myParentFragmentEvaluator = parentFragmentEvaluator;
+  }
+
+  public void setStatements(Evaluator[] evaluators) {
+    myStatements = evaluators;
+  }
+
+  public Value getValue(String localName, VirtualMachineProxyImpl vm) throws EvaluateException {
+    if(!mySyntheticLocals.containsKey(localName)) {
+      if(myParentFragmentEvaluator != null){
+        return myParentFragmentEvaluator.getValue(localName, vm);
+      } else {
+        throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.variable.not.declared", localName));
+      }
+    }
+    Object value = mySyntheticLocals.get(localName);
+    if(value instanceof Value) {
+      return (Value)value;
+    }
+    else if(value == null) {
+      return null;
+    }
+    else if(value instanceof Boolean) {
+      return vm.mirrorOf(((Boolean)value).booleanValue());
+    }
+    else if(value instanceof Byte) {
+      return vm.mirrorOf(((Byte)value).byteValue());
+    }
+    else if(value instanceof Character) {
+      return vm.mirrorOf(((Character)value).charValue());
+    }
+    else if(value instanceof Short) {
+      return vm.mirrorOf(((Short)value).shortValue());
+    }
+    else if(value instanceof Integer) {
+      return vm.mirrorOf(((Integer)value).intValue());
+    }
+    else if(value instanceof Long) {
+      return vm.mirrorOf(((Long)value).longValue());
+    }
+    else if(value instanceof Float) {
+      return vm.mirrorOf(((Float)value).floatValue());
+    }
+    else if(value instanceof Double) {
+      return vm.mirrorOf(((Double)value).doubleValue());
+    }
+    else if(value instanceof String) {
+      return vm.mirrorOf((String)value);
+    }
+    else {
+      LOG.error("unknown default initializer type " + value.getClass().getName());
+      return null;
+    }
+  }
+
+  private boolean hasValue(String localName) {
+    if(!mySyntheticLocals.containsKey(localName)) {
+      if(myParentFragmentEvaluator != null){
+        return myParentFragmentEvaluator.hasValue(localName);
+      } else {
+        return false;
+      }
+    } else {
+      return true;
+    }
+  }
+
+  public void setInitialValue(String localName, Object value) throws EvaluateException {
+    LOG.assertTrue(!(value instanceof Value), "use setValue for jdi values");
+    if(hasValue(localName)) {
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.variable.already.declared", localName));
+    }
+    mySyntheticLocals.put(localName, value);
+  }
+
+  public void setValue(String localName, Value value) throws EvaluateException {
+    if(!mySyntheticLocals.containsKey(localName)) {
+      if(myParentFragmentEvaluator != null){
+        myParentFragmentEvaluator.setValue(localName, value);
+      } else {
+        throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.variable.not.declared", localName));
+      }
+    }
+    mySyntheticLocals.put(localName, value);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ConditionalExpressionEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ConditionalExpressionEvaluator.java
new file mode 100644
index 0000000..3514d35
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ConditionalExpressionEvaluator.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class ConditionalExpressionEvaluator
+ * @author Jeka
+ */
+package com.intellij.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.DebuggerBundle;
+import com.sun.jdi.BooleanValue;
+import com.sun.jdi.Value;
+
+class ConditionalExpressionEvaluator implements Evaluator {
+  private final Evaluator myConditionEvaluator;
+  private final Evaluator myThenEvaluator;
+  private final Evaluator myElseEvaluator;
+
+  public ConditionalExpressionEvaluator(Evaluator conditionEvaluator, Evaluator thenEvaluator, Evaluator elseEvaluator) {
+    myConditionEvaluator = conditionEvaluator;
+    myThenEvaluator = thenEvaluator;
+    myElseEvaluator = elseEvaluator;
+  }
+
+  public Modifier getModifier() {
+    return null;
+  }
+
+  public Object evaluate(EvaluationContextImpl context) throws EvaluateException {
+    Value condition = (Value)myConditionEvaluator.evaluate(context);
+    if (condition == null || !(condition instanceof BooleanValue)) {
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.boolean.condition.expected"));
+    }
+    return ((BooleanValue)condition).booleanValue()? myThenEvaluator.evaluate(context) : myElseEvaluator.evaluate(context);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ContinueException.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ContinueException.java
new file mode 100644
index 0000000..fd0dff3
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ContinueException.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+
+/**
+ * @authorlex
+ */
+public class ContinueException extends EvaluateException{
+  private final String myLabelName;
+
+  public ContinueException(String labelName) {
+    super(DebuggerBundle.message("evaluation.error.lebeled.loops.not.found", labelName), null);
+    myLabelName = labelName;
+  }
+
+  public String getLabelName() {
+    return myLabelName;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/DisableGC.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/DisableGC.java
new file mode 100644
index 0000000..1c5e718
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/DisableGC.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2000-2010 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.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.sun.jdi.ObjectReference;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: 9/30/10
+ */
+public class DisableGC implements Evaluator{
+  private final Evaluator myDelegate;
+
+  public DisableGC(Evaluator delegate) {
+    myDelegate = delegate;
+  }
+
+  public Object evaluate(EvaluationContextImpl context) throws EvaluateException {
+    final Object result = myDelegate.evaluate(context);
+    if (result instanceof ObjectReference) {
+      context.getSuspendContext().keep((ObjectReference)result);
+    }
+    return result;
+  }
+
+  public Evaluator getDelegate() {
+    return myDelegate;
+  }
+
+  public Modifier getModifier() {
+    return myDelegate.getModifier();
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/Evaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/Evaluator.java
new file mode 100644
index 0000000..9c2efc4
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/Evaluator.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Interface Evaluator
+ * @author Jeka
+ */
+package com.intellij.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+
+public interface Evaluator {
+  /**
+   * @throws com.intellij.debugger.engine.evaluation.EvaluateException
+   */
+  Object evaluate(EvaluationContextImpl context) throws EvaluateException;
+
+  /**
+   * In order to obtain a modifier the expression must be evaluated first
+   * @return a modifier object allowing to set a value in case the expression is lvalue,
+   *         otherwise null is returned
+   */
+  Modifier getModifier();
+}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/EvaluatorBuilderImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/EvaluatorBuilderImpl.java
new file mode 100644
index 0000000..a596e30
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/EvaluatorBuilderImpl.java
@@ -0,0 +1,1254 @@
+/*
+ * Copyright 2000-2012 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.
+ */
+
+/*
+ * Class EvaluatorBuilderImpl
+ * @author Jeka
+ */
+package com.intellij.debugger.engine.evaluation.expression;
+
+import com.intellij.codeInsight.daemon.JavaErrorMessages;
+import com.intellij.codeInsight.daemon.impl.HighlightInfo;
+import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil;
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.SourcePosition;
+import com.intellij.debugger.engine.ContextUtil;
+import com.intellij.debugger.engine.DebuggerUtils;
+import com.intellij.debugger.engine.JVMName;
+import com.intellij.debugger.engine.JVMNameUtil;
+import com.intellij.debugger.engine.evaluation.*;
+import com.intellij.debugger.ui.DebuggerEditorImpl;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.*;
+import com.intellij.psi.impl.JavaConstantExpressionEvaluator;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.tree.IElementType;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.PsiTypesUtil;
+import com.intellij.psi.util.TypeConversionUtil;
+import com.intellij.util.IncorrectOperationException;
+import com.sun.jdi.Value;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class EvaluatorBuilderImpl implements EvaluatorBuilder {
+  private static final EvaluatorBuilderImpl ourInstance = new EvaluatorBuilderImpl();
+
+  private EvaluatorBuilderImpl() {
+  }
+
+  public static EvaluatorBuilder getInstance() {
+    return ourInstance;
+  }
+
+  public static ExpressionEvaluator build(final TextWithImports text, final PsiElement contextElement, final SourcePosition position) throws EvaluateException {
+    if (contextElement == null) {
+      throw EvaluateExceptionUtil.CANNOT_FIND_SOURCE_CLASS;
+    }
+
+    final Project project = contextElement.getProject();
+
+    CodeFragmentFactory factory = DebuggerEditorImpl.findAppropriateFactory(text, contextElement);
+    PsiCodeFragment codeFragment = new CodeFragmentFactoryContextWrapper(factory).createCodeFragment(text, contextElement, project);
+    if(codeFragment == null) {
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", text.getText()));
+    }
+    codeFragment.forceResolveScope(GlobalSearchScope.allScope(project));
+    DebuggerUtils.checkSyntax(codeFragment);
+
+    EvaluatorBuilder evaluatorBuilder = factory.getEvaluatorBuilder();
+
+    return evaluatorBuilder.build(codeFragment, position);
+  }
+
+  public ExpressionEvaluator build(final PsiElement codeFragment, final SourcePosition position) throws EvaluateException {
+    return new Builder(position).buildElement(codeFragment);
+  }
+
+  private static class Builder extends JavaElementVisitor {
+    private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilderImpl");
+    private Evaluator myResult = null;
+    private PsiClass myContextPsiClass;
+    private CodeFragmentEvaluator myCurrentFragmentEvaluator;
+    private final Set<JavaCodeFragment> myVisitedFragments = new HashSet<JavaCodeFragment>();
+    @Nullable
+    private final SourcePosition myPosition;
+
+    private Builder(@Nullable SourcePosition position) {
+      myPosition = position;
+    }
+
+    @Override
+    public void visitCodeFragment(JavaCodeFragment codeFragment) {
+      myVisitedFragments.add(codeFragment);
+      ArrayList<Evaluator> evaluators = new ArrayList<Evaluator>();
+
+      CodeFragmentEvaluator oldFragmentEvaluator = myCurrentFragmentEvaluator;
+      myCurrentFragmentEvaluator = new CodeFragmentEvaluator(oldFragmentEvaluator);
+
+      for (PsiElement child = codeFragment.getFirstChild(); child != null; child = child.getNextSibling()) {
+        child.accept(this);
+        if(myResult != null) {
+          evaluators.add(myResult);
+        }
+        myResult = null;
+      }
+
+      myCurrentFragmentEvaluator.setStatements(evaluators.toArray(new Evaluator[evaluators.size()]));
+      myResult = myCurrentFragmentEvaluator;
+
+      myCurrentFragmentEvaluator = oldFragmentEvaluator;
+    }
+
+    @Override
+    public void visitErrorElement(PsiErrorElement element) {
+      throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", element.getText()));
+    }
+
+    @Override
+    public void visitAssignmentExpression(PsiAssignmentExpression expression) {
+      final PsiExpression rExpression = expression.getRExpression();
+      if(rExpression == null) {
+        throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText())); return;
+      }
+
+      rExpression.accept(this);
+      Evaluator rEvaluator = myResult;
+
+      if(expression.getOperationTokenType() != JavaTokenType.EQ) {
+        throwEvaluateException(DebuggerBundle.message("evaluation.error.operation.not.supported", expression.getOperationSign().getText()));
+      }
+
+      final PsiExpression lExpression = expression.getLExpression();
+
+      final PsiType lType = lExpression.getType();
+      if(lType == null) {
+        throwEvaluateException(DebuggerBundle.message("evaluation.error.unknown.expression.type", lExpression.getText()));
+      }
+
+      if(!TypeConversionUtil.areTypesAssignmentCompatible(lType, rExpression) && rExpression.getType() != null) {
+        throwEvaluateException(DebuggerBundle.message("evaluation.error.incompatible.types", expression.getOperationSign().getText()));
+      }
+      lExpression.accept(this);
+      Evaluator lEvaluator = myResult;
+
+      rEvaluator = handleAssignmentBoxingAndPrimitiveTypeConversions(lType, rExpression.getType(), rEvaluator);
+      
+      myResult = new AssignmentEvaluator(lEvaluator, rEvaluator);
+    }
+
+    // returns rEvaluator possibly wrapped with boxing/unboxing and casting evaluators
+    private static Evaluator handleAssignmentBoxingAndPrimitiveTypeConversions(PsiType lType, PsiType rType, Evaluator rEvaluator) {
+      final PsiType unboxedLType = PsiPrimitiveType.getUnboxedType(lType);
+
+      if (unboxedLType != null) {
+        if (rType instanceof PsiPrimitiveType && !PsiType.NULL.equals(rType)) {
+          if (!rType.equals(unboxedLType)) {
+            rEvaluator = new TypeCastEvaluator(rEvaluator, unboxedLType.getCanonicalText(), true);
+          }
+          rEvaluator = new BoxingEvaluator(rEvaluator);
+        }
+      }
+      else {
+        // either primitive type or not unboxable type
+        if (lType instanceof PsiPrimitiveType) {
+          if (rType instanceof PsiClassType) {
+            rEvaluator = new UnBoxingEvaluator(rEvaluator);
+          }
+          final PsiPrimitiveType unboxedRType = PsiPrimitiveType.getUnboxedType(rType);
+          final PsiType _rType = unboxedRType != null? unboxedRType : rType;
+          if (_rType instanceof PsiPrimitiveType && !PsiType.NULL.equals(_rType)) {
+            if (!lType.equals(_rType)) {
+              rEvaluator = new TypeCastEvaluator(rEvaluator, lType.getCanonicalText(), true);
+            }
+          }
+        }
+      }
+      return rEvaluator;
+    }
+
+    @Override
+    public void visitStatement(PsiStatement statement) {
+      throwEvaluateException(DebuggerBundle.message("evaluation.error.statement.not.supported", statement.getText()));
+    }
+
+    @Override
+    public void visitBlockStatement(PsiBlockStatement statement) {
+      PsiStatement[] statements = statement.getCodeBlock().getStatements();
+      Evaluator [] evaluators = new Evaluator[statements.length];
+      for (int i = 0; i < statements.length; i++) {
+        PsiStatement psiStatement = statements[i];
+        psiStatement.accept(this);
+        evaluators[i] = new DisableGC(myResult);
+        myResult = null;
+      }
+      myResult = new BlockStatementEvaluator(evaluators);
+    }
+
+    @Override
+    public void visitWhileStatement(PsiWhileStatement statement) {
+      PsiStatement body = statement.getBody();
+      if(body == null) return;
+      body.accept(this);
+      Evaluator bodyEvaluator = myResult;
+
+      PsiExpression condition = statement.getCondition();
+      if(condition == null) return;
+      condition.accept(this);
+      String label = null;
+      if(statement.getParent() instanceof PsiLabeledStatement) {
+        label = ((PsiLabeledStatement)statement.getParent()).getLabelIdentifier().getText();
+      }
+      myResult = new WhileStatementEvaluator(myResult, bodyEvaluator, label);
+    }
+
+    @Override
+    public void visitForStatement(PsiForStatement statement) {
+      PsiStatement initializer = statement.getInitialization();
+      Evaluator initializerEvaluator = null;
+      if(initializer != null){
+        initializer.accept(this);
+        initializerEvaluator = myResult;
+      }
+
+      PsiExpression condition = statement.getCondition();
+      Evaluator conditionEvaluator = null;
+      if(condition != null) {
+        condition.accept(this);
+        conditionEvaluator = myResult;
+      }
+
+      PsiStatement update = statement.getUpdate();
+      Evaluator updateEvaluator = null;
+      if(update != null){
+        update.accept(this);
+        updateEvaluator = myResult;
+      }
+
+      PsiStatement body = statement.getBody();
+      if(body == null) return;
+      body.accept(this);
+      Evaluator bodyEvaluator = myResult;
+
+      String label = null;
+      if(statement.getParent() instanceof PsiLabeledStatement) {
+        label = ((PsiLabeledStatement)statement.getParent()).getLabelIdentifier().getText();
+      }
+      myResult = new ForStatementEvaluator(initializerEvaluator, conditionEvaluator, updateEvaluator, bodyEvaluator, label);
+    }
+
+    @Override
+    public void visitIfStatement(PsiIfStatement statement) {
+      PsiStatement thenBranch = statement.getThenBranch();
+      if(thenBranch == null) return;
+      thenBranch.accept(this);
+      Evaluator thenEvaluator = myResult;
+
+      PsiStatement elseBranch = statement.getElseBranch();
+      Evaluator elseEvaluator = null;
+      if(elseBranch != null){
+        elseBranch.accept(this);
+        elseEvaluator = myResult;
+      }
+
+      PsiExpression condition = statement.getCondition();
+      if(condition == null) return;
+      condition.accept(this);
+
+      myResult = new IfStatementEvaluator(myResult, thenEvaluator, elseEvaluator);
+    }
+
+    @Override
+    public void visitBreakStatement(PsiBreakStatement statement) {
+      PsiIdentifier labelIdentifier = statement.getLabelIdentifier();
+      myResult = BreakContinueStatementEvaluator.createBreakEvaluator(labelIdentifier != null ? labelIdentifier.getText() : null);
+    }
+
+    @Override
+    public void visitContinueStatement(PsiContinueStatement statement) {
+      PsiIdentifier labelIdentifier = statement.getLabelIdentifier();
+      myResult = BreakContinueStatementEvaluator.createContinueEvaluator(labelIdentifier != null ? labelIdentifier.getText() : null);
+    }
+
+    @Override
+    public void visitExpressionStatement(PsiExpressionStatement statement) {
+      statement.getExpression().accept(this);
+    }
+
+    @Override
+    public void visitExpression(PsiExpression expression) {
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("visitExpression " + expression);
+      }
+    }
+
+    @Override
+    public void visitPolyadicExpression(PsiPolyadicExpression wideExpression) {
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("visitPolyadicExpression " + wideExpression);
+      }
+      PsiExpression[] operands = wideExpression.getOperands();
+      operands[0].accept(this);
+      Evaluator result = myResult;
+      PsiType lType = operands[0].getType();
+      for (int i = 1; i < operands.length; i++) {
+        PsiExpression expression = operands[i];
+        if (expression == null) {
+          throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", wideExpression.getText()));
+          return;
+        }
+        expression.accept(this);
+        Evaluator rResult = myResult;
+        IElementType opType = wideExpression.getOperationTokenType();
+        PsiType rType = expression.getType();
+        if (rType == null) {
+          throwEvaluateException(DebuggerBundle.message("evaluation.error.unknown.expression.type", expression.getText()));
+        }
+        final PsiType typeForBinOp = TypeConversionUtil.calcTypeForBinaryExpression(lType, rType, opType, true);
+        if (typeForBinOp == null) {
+          throwEvaluateException(DebuggerBundle.message("evaluation.error.unknown.expression.type", wideExpression.getText()));
+        }
+        myResult = createBinaryEvaluator(result, lType, rResult, rType, opType, typeForBinOp);
+        lType = typeForBinOp;
+        result = myResult;
+      }
+    }
+
+    // constructs binary evaluator handling unboxing and numeric promotion issues
+    private static BinaryExpressionEvaluator createBinaryEvaluator(Evaluator lResult,
+                                                                   PsiType lType,
+                                                                   Evaluator rResult,
+                                                                   @NotNull PsiType rType,
+                                                                   @NotNull IElementType operation,
+                                                                   @NotNull PsiType expressionExpectedType) {
+      // handle unboxing if neccesary
+      if (isUnboxingInBinaryExpressionApplicable(lType, rType, operation)) {
+        if (rType instanceof PsiClassType && UnBoxingEvaluator.isTypeUnboxable(rType.getCanonicalText())) {
+          rResult = new UnBoxingEvaluator(rResult);
+        }
+        if (lType instanceof PsiClassType && UnBoxingEvaluator.isTypeUnboxable(lType.getCanonicalText())) {
+          lResult = new UnBoxingEvaluator(lResult);
+        }
+      }
+      if (isBinaryNumericPromotionApplicable(lType, rType, operation)) {
+        PsiType _lType = lType;
+        final PsiPrimitiveType unboxedLType = PsiPrimitiveType.getUnboxedType(lType);
+        if (unboxedLType != null) {
+          _lType = unboxedLType;
+        }
+
+        PsiType _rType = rType;
+        final PsiPrimitiveType unboxedRType = PsiPrimitiveType.getUnboxedType(rType);
+        if (unboxedRType != null) {
+          _rType = unboxedRType;
+        }
+
+        // handle numeric promotion
+        if (PsiType.DOUBLE.equals(_lType)) {
+          if (TypeConversionUtil.areTypesConvertible(_rType, PsiType.DOUBLE)) {
+            rResult = new TypeCastEvaluator(rResult, PsiType.DOUBLE.getCanonicalText(), true);
+          }
+        }
+        else if (PsiType.DOUBLE.equals(_rType)) {
+          if (TypeConversionUtil.areTypesConvertible(_lType, PsiType.DOUBLE)) {
+            lResult = new TypeCastEvaluator(lResult, PsiType.DOUBLE.getCanonicalText(), true);
+          }
+        }
+        else if (PsiType.FLOAT.equals(_lType)) {
+          if (TypeConversionUtil.areTypesConvertible(_rType, PsiType.FLOAT)) {
+            rResult = new TypeCastEvaluator(rResult, PsiType.FLOAT.getCanonicalText(), true);
+          }
+        }
+        else if (PsiType.FLOAT.equals(_rType)) {
+          if (TypeConversionUtil.areTypesConvertible(_lType, PsiType.FLOAT)) {
+            lResult = new TypeCastEvaluator(lResult, PsiType.FLOAT.getCanonicalText(), true);
+          }
+        }
+        else if (PsiType.LONG.equals(_lType)) {
+          if (TypeConversionUtil.areTypesConvertible(_rType, PsiType.LONG)) {
+            rResult = new TypeCastEvaluator(rResult, PsiType.LONG.getCanonicalText(), true);
+          }
+        }
+        else if (PsiType.LONG.equals(_rType)) {
+          if (TypeConversionUtil.areTypesConvertible(_lType, PsiType.LONG)) {
+            lResult = new TypeCastEvaluator(lResult, PsiType.LONG.getCanonicalText(), true);
+          }
+        }
+        else {
+          if (!PsiType.INT.equals(_lType) && TypeConversionUtil.areTypesConvertible(_lType, PsiType.INT)) {
+            lResult = new TypeCastEvaluator(lResult, PsiType.INT.getCanonicalText(), true);
+          }
+          if (!PsiType.INT.equals(_rType) && TypeConversionUtil.areTypesConvertible(_rType, PsiType.INT)) {
+            rResult = new TypeCastEvaluator(rResult, PsiType.INT.getCanonicalText(), true);
+          }
+        }
+      }
+
+      return new BinaryExpressionEvaluator(lResult, rResult, operation, expressionExpectedType.getCanonicalText());
+    }
+
+    private static boolean isBinaryNumericPromotionApplicable(PsiType lType, PsiType rType, IElementType opType) {
+      if (lType == null || rType == null) {
+        return false;
+      }
+      if (!TypeConversionUtil.isNumericType(lType) || !TypeConversionUtil.isNumericType(rType)) {
+        return false;
+      }
+      if (opType == JavaTokenType.EQEQ || opType == JavaTokenType.NE) {
+        if (PsiType.NULL.equals(lType) || PsiType.NULL.equals(rType)) {
+          return false;
+        }
+        if (lType instanceof PsiClassType && rType instanceof PsiClassType) {
+          return false;
+        }
+        if (lType instanceof PsiClassType) {
+          return PsiPrimitiveType.getUnboxedType(lType) != null; // should be unboxable
+        }
+        if (rType instanceof PsiClassType) {
+          return PsiPrimitiveType.getUnboxedType(rType) != null; // should be unboxable
+        }
+        return true;
+      }
+
+      return opType == JavaTokenType.ASTERISK ||
+          opType == JavaTokenType.DIV         ||
+          opType == JavaTokenType.PERC        ||
+          opType == JavaTokenType.PLUS        ||
+          opType == JavaTokenType.MINUS       ||
+          opType == JavaTokenType.LT          ||
+          opType == JavaTokenType.LE          ||
+          opType == JavaTokenType.GT          ||
+          opType == JavaTokenType.GE          ||
+          opType == JavaTokenType.AND         ||
+          opType == JavaTokenType.XOR         ||
+          opType == JavaTokenType.OR;
+
+    }
+
+    private static boolean isUnboxingInBinaryExpressionApplicable(PsiType lType, PsiType rType, IElementType opCode) {
+      if (PsiType.NULL.equals(lType) || PsiType.NULL.equals(rType)) {
+        return false;
+      }
+      // handle '==' and '!=' separately
+      if (opCode == JavaTokenType.EQEQ || opCode == JavaTokenType.NE) {
+        return lType instanceof PsiPrimitiveType && rType instanceof PsiClassType ||
+               lType instanceof PsiClassType     && rType instanceof PsiPrimitiveType;
+      }
+      // all other operations at least one should be of class type
+      return lType instanceof PsiClassType || rType instanceof PsiClassType;
+    }
+
+    /**
+     * @param type
+     * @return promotion type to cast to or null if no casting needed
+     */
+    @Nullable
+    private static PsiType calcUnaryNumericPromotionType(PsiPrimitiveType type) {
+      if (PsiType.BYTE.equals(type) || PsiType.SHORT.equals(type) || PsiType.CHAR.equals(type) || PsiType.INT.equals(type)) {
+        return PsiType.INT;
+      }
+      return null;
+    }
+
+    @Override
+    public void visitDeclarationStatement(PsiDeclarationStatement statement) {
+      List<Evaluator> evaluators = new ArrayList<Evaluator>();
+
+      PsiElement[] declaredElements = statement.getDeclaredElements();
+      for (PsiElement declaredElement : declaredElements) {
+        if (declaredElement instanceof PsiLocalVariable) {
+          if (myCurrentFragmentEvaluator != null) {
+            final PsiLocalVariable localVariable = (PsiLocalVariable)declaredElement;
+
+            final PsiType lType = localVariable.getType();
+
+            PsiElementFactory elementFactory = JavaPsiFacade.getInstance(localVariable.getProject()).getElementFactory();
+            try {
+              PsiExpression initialValue = elementFactory.createExpressionFromText(PsiTypesUtil.getDefaultValueOfType(lType), null);
+              Object value = JavaConstantExpressionEvaluator.computeConstantExpression(initialValue, true);
+              myCurrentFragmentEvaluator.setInitialValue(localVariable.getName(), value);
+            }
+            catch (IncorrectOperationException e) {
+              LOG.error(e);
+            }
+            catch (EvaluateException e) {
+              throw new EvaluateRuntimeException(e);
+            }
+
+            PsiExpression initializer = localVariable.getInitializer();
+            if (initializer != null) {
+              try {
+                if (!TypeConversionUtil.areTypesAssignmentCompatible(lType, initializer)) {
+                  throwEvaluateException(
+                    DebuggerBundle.message("evaluation.error.incompatible.variable.initializer.type", localVariable.getName()));
+                }
+                final PsiType rType = initializer.getType();
+                initializer.accept(this);
+                Evaluator rEvaluator = myResult;
+
+                PsiExpression localVarReference = elementFactory.createExpressionFromText(localVariable.getName(), initializer);
+
+                localVarReference.accept(this);
+                Evaluator lEvaluator = myResult;
+                rEvaluator = handleAssignmentBoxingAndPrimitiveTypeConversions(localVarReference.getType(), rType, rEvaluator);
+
+                Evaluator assignment = new AssignmentEvaluator(lEvaluator, rEvaluator);
+                evaluators.add(assignment);
+              }
+              catch (IncorrectOperationException e) {
+                LOG.error(e);
+              }
+            }
+          }
+          else {
+            throw new EvaluateRuntimeException(new EvaluateException(
+              DebuggerBundle.message("evaluation.error.local.variable.declarations.not.supported"), null));
+          }
+        }
+        else {
+          throw new EvaluateRuntimeException(new EvaluateException(
+            DebuggerBundle.message("evaluation.error.unsupported.declaration", declaredElement.getText()), null));
+        }
+      }
+
+      if(!evaluators.isEmpty()) {
+        CodeFragmentEvaluator codeFragmentEvaluator = new CodeFragmentEvaluator(myCurrentFragmentEvaluator);
+        codeFragmentEvaluator.setStatements(evaluators.toArray(new Evaluator[evaluators.size()]));
+        myResult = codeFragmentEvaluator;
+      } else {
+        myResult = null;
+      }
+    }
+
+    @Override
+    public void visitConditionalExpression(PsiConditionalExpression expression) {
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("visitConditionalExpression " + expression);
+      }
+      final PsiExpression thenExpression = expression.getThenExpression();
+      final PsiExpression elseExpression = expression.getElseExpression();
+      if (thenExpression == null || elseExpression == null){
+        throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText())); return;
+      }
+      PsiExpression condition = expression.getCondition();
+      condition.accept(this);
+      if (myResult == null) {
+        throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", condition.getText())); return;
+      }
+      Evaluator conditionEvaluator = myResult;
+      thenExpression.accept(this);
+      if (myResult == null) {
+        throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", thenExpression.getText())); return;
+      }
+      Evaluator thenEvaluator = myResult;
+      elseExpression.accept(this);
+      if (myResult == null) {
+        throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", elseExpression.getText())); return;
+      }
+      Evaluator elseEvaluator = myResult;
+      myResult = new ConditionalExpressionEvaluator(conditionEvaluator, thenEvaluator, elseEvaluator);
+    }
+
+    @Override
+    public void visitReferenceExpression(PsiReferenceExpression expression) {
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("visitReferenceExpression " + expression);
+      }
+      PsiExpression qualifier = expression.getQualifierExpression();
+      JavaResolveResult resolveResult = expression.advancedResolve(true);
+      PsiElement element = resolveResult.getElement();
+
+      if (element instanceof PsiLocalVariable || element instanceof PsiParameter) {
+        final Value labeledValue = element.getUserData(CodeFragmentFactoryContextWrapper.LABEL_VARIABLE_VALUE_KEY);
+        if (labeledValue != null) {
+          myResult = new IdentityEvaluator(labeledValue);
+          return;
+        }
+        //synthetic variable
+        final PsiFile containingFile = element.getContainingFile();
+        if(containingFile instanceof PsiCodeFragment && myCurrentFragmentEvaluator != null && myVisitedFragments.contains(containingFile)) {
+          // psiVariable may live in PsiCodeFragment not only in debugger editors, for example Fabrique has such variables.
+          // So treat it as synthetic var only when this code fragment is located in DebuggerEditor,
+          // that's why we need to check that containing code fragment is the one we visited
+          myResult = new SyntheticVariableEvaluator(myCurrentFragmentEvaluator, ((PsiVariable)element).getName());
+          return;
+        }
+        // local variable
+        final PsiVariable psiVar = (PsiVariable)element;
+        final String localName = psiVar.getName();
+        PsiClass variableClass = getContainingClass(psiVar);
+        if (getContextPsiClass() == null || getContextPsiClass().equals(variableClass)) {
+          final LocalVariableEvaluator localVarEvaluator = new LocalVariableEvaluator(localName, ContextUtil.isJspImplicit(element));
+          if (psiVar instanceof PsiParameter) {
+            final PsiParameter param = (PsiParameter)psiVar;
+            final PsiParameterList paramList = PsiTreeUtil.getParentOfType(param, PsiParameterList.class, true);
+            if (paramList != null) {
+              localVarEvaluator.setParameterIndex(paramList.getParameterIndex(param));
+            }
+          }
+          myResult = localVarEvaluator;
+          return;
+        }
+        // the expression references final var outside the context's class (in some of the outer classes)
+        int iterationCount = 0;
+        PsiClass aClass = getOuterClass(getContextPsiClass());
+        while (aClass != null && !aClass.equals(variableClass)) {
+          iterationCount++;
+          aClass = getOuterClass(aClass);
+        }
+        if (aClass != null) {
+          PsiExpression initializer = psiVar.getInitializer();
+          if(initializer != null) {
+            Object value = JavaPsiFacade.getInstance(psiVar.getProject()).getConstantEvaluationHelper().computeConstantExpression(initializer);
+            if(value != null) {
+              PsiType type = resolveResult.getSubstitutor().substitute(psiVar.getType());
+              myResult = new LiteralEvaluator(value, type.getCanonicalText());
+              return;
+            }
+          }
+          Evaluator objectEvaluator = new ThisEvaluator(iterationCount);
+          //noinspection HardCodedStringLiteral
+          final PsiClass classAt = myPosition != null? JVMNameUtil.getClassAt(myPosition) : null;
+          FieldEvaluator.TargetClassFilter filter = FieldEvaluator.createClassFilter(classAt != null? classAt : getContextPsiClass());
+          myResult = new FieldEvaluator(objectEvaluator, filter, "val$" + localName);
+          return;
+        }
+        throwEvaluateException(DebuggerBundle.message("evaluation.error.local.variable.missing.from.class.closure", localName));
+      }
+      else if (element instanceof PsiField) {
+        final PsiField psiField = (PsiField)element;
+        final PsiClass fieldClass = psiField.getContainingClass();
+        if(fieldClass == null) {
+          throwEvaluateException(DebuggerBundle.message("evaluation.error.cannot.resolve.field.class", psiField.getName())); return;
+        }
+        Evaluator objectEvaluator;
+        if (psiField.hasModifierProperty(PsiModifier.STATIC)) {
+          objectEvaluator = new TypeEvaluator(JVMNameUtil.getContextClassJVMQualifiedName(SourcePosition.createFromElement(psiField)));
+        }
+        else if(qualifier != null) {
+          qualifier.accept(this);
+          objectEvaluator = myResult;
+        }
+        else if (fieldClass.equals(getContextPsiClass()) || getContextPsiClass().isInheritor(fieldClass, true)) {
+            objectEvaluator = new ThisEvaluator();
+        }
+        else {  // myContextPsiClass != fieldClass && myContextPsiClass is not a subclass of fieldClass
+          int iterationCount = 0;
+          PsiClass aClass = getContextPsiClass();
+          while (aClass != null && !(aClass.equals(fieldClass) || aClass.isInheritor(fieldClass, true))) {
+            iterationCount++;
+            aClass = getOuterClass(aClass);
+          }
+          if (aClass == null) {
+            throwEvaluateException(DebuggerBundle.message("evaluation.error.cannot.sources.for.field.class", psiField.getName()));
+          }
+          objectEvaluator = new ThisEvaluator(iterationCount);
+        }
+        myResult = new FieldEvaluator(objectEvaluator, FieldEvaluator.createClassFilter(fieldClass), psiField.getName());
+      }
+      else {
+        //let's guess what this could be
+        PsiElement nameElement = expression.getReferenceNameElement(); // get "b" part
+        String name;
+        if (nameElement instanceof PsiIdentifier) {
+          name = nameElement.getText();
+        }
+        else {
+          //noinspection HardCodedStringLiteral
+          final String elementDisplayString = nameElement != null ? nameElement.getText() : "(null)";
+          throwEvaluateException(DebuggerBundle.message("evaluation.error.identifier.expected", elementDisplayString));
+          return;
+        }
+
+        if(qualifier != null) {
+          final PsiElement qualifierTarget = qualifier instanceof PsiReferenceExpression
+                                             ? ((PsiReferenceExpression)qualifier).resolve() : null;
+          if (qualifierTarget instanceof PsiClass) {
+            // this is a call to a 'static' field
+            PsiClass psiClass = (PsiClass)qualifierTarget;
+            final JVMName typeName = JVMNameUtil.getJVMQualifiedName(psiClass);
+            myResult = new FieldEvaluator(new TypeEvaluator(typeName), FieldEvaluator.createClassFilter(psiClass), name);
+          }
+          else {
+            PsiType type = qualifier.getType();
+            if(type == null) {
+              throwEvaluateException(DebuggerBundle.message("evaluation.error.qualifier.type.unknown", qualifier.getText()));
+            }
+
+            qualifier.accept(this);
+            if (myResult == null) {
+              throwEvaluateException(DebuggerBundle.message("evaluation.error.cannot.evaluate.qualifier", qualifier.getText()));
+            }
+
+            myResult = new FieldEvaluator(myResult, FieldEvaluator.createClassFilter(type), name);
+          }
+        }
+        else {
+          myResult = new LocalVariableEvaluator(name, false);
+        }
+      }
+    }
+
+    private static void throwEvaluateException(String message) throws EvaluateRuntimeException {
+      //noinspection ThrowableResultOfMethodCallIgnored
+      throw new EvaluateRuntimeException(EvaluateExceptionUtil.createEvaluateException(message));
+    }
+
+    @Override
+    public void visitSuperExpression(PsiSuperExpression expression) {
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("visitSuperExpression " + expression);
+      }
+      final int iterationCount = calcIterationCount(expression.getQualifier());
+      myResult = new SuperEvaluator(iterationCount);
+    }
+
+    @Override
+    public void visitThisExpression(PsiThisExpression expression) {
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("visitThisExpression " + expression);
+      }
+      final int iterationCount = calcIterationCount(expression.getQualifier());
+      myResult = new ThisEvaluator(iterationCount);
+    }
+
+    private int calcIterationCount(final PsiJavaCodeReferenceElement qualifier) {
+      int iterationCount = 0;
+      if (qualifier != null) {
+        PsiElement targetClass = qualifier.resolve();
+        if (targetClass == null || getContextPsiClass() == null) {
+          throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", qualifier.getText()));
+        }
+        try {
+          PsiClass aClass = getContextPsiClass();
+          while (aClass != null && !aClass.equals(targetClass)) {
+            iterationCount++;
+            aClass = getOuterClass(aClass);
+          }
+        }
+        catch (Exception e) {
+          //noinspection ThrowableResultOfMethodCallIgnored
+          throw new EvaluateRuntimeException(EvaluateExceptionUtil.createEvaluateException(e));
+        }
+      }
+      return iterationCount;
+    }
+
+    @Override
+    public void visitInstanceOfExpression(PsiInstanceOfExpression expression) {
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("visitInstanceOfExpression " + expression);
+      }
+      PsiTypeElement checkType = expression.getCheckType();
+      if(checkType == null) {
+        throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText()));
+        return;
+      }
+      PsiType type = checkType.getType();
+      expression.getOperand().accept(this);
+//    ClassObjectEvaluator typeEvaluator = new ClassObjectEvaluator(type.getCanonicalText());
+      Evaluator operandEvaluator = myResult;
+      myResult = new InstanceofEvaluator(operandEvaluator, new TypeEvaluator(JVMNameUtil.getJVMQualifiedName(type)));
+    }
+
+    @Override
+    public void visitParenthesizedExpression(PsiParenthesizedExpression expression) {
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("visitParenthesizedExpression " + expression);
+      }
+      PsiExpression expr = expression.getExpression();
+      if (expr != null){
+        expr.accept(this);
+      }
+    }
+
+    @Override
+    public void visitPostfixExpression(PsiPostfixExpression expression) {
+      if(expression.getType() == null) {
+        throwEvaluateException(DebuggerBundle.message("evaluation.error.unknown.expression.type", expression.getText()));
+      }
+
+      final PsiExpression operandExpression = expression.getOperand();
+      operandExpression.accept(this);
+
+      final Evaluator operandEvaluator = myResult;
+
+      final IElementType operation = expression.getOperationTokenType();
+      final PsiType operandType = operandExpression.getType();
+      @Nullable final PsiType unboxedOperandType = PsiPrimitiveType.getUnboxedType(operandType);
+
+      Evaluator incrementImpl = createBinaryEvaluator(
+        operandEvaluator, operandType,
+        new LiteralEvaluator(Integer.valueOf(1), "int"), PsiType.INT,
+        operation == JavaTokenType.PLUSPLUS ? JavaTokenType.PLUS : JavaTokenType.MINUS,
+        unboxedOperandType!= null? unboxedOperandType : operandType
+      );
+      if (unboxedOperandType != null) {
+        incrementImpl = new BoxingEvaluator(incrementImpl);
+      }
+      myResult = new PostfixOperationEvaluator(operandEvaluator, incrementImpl);
+    }
+
+    @Override
+    public void visitPrefixExpression(final PsiPrefixExpression expression) {
+      final PsiType expressionType = expression.getType();
+      if(expressionType == null) {
+        throwEvaluateException(DebuggerBundle.message("evaluation.error.unknown.expression.type", expression.getText()));
+      }
+
+      final PsiExpression operandExpression = expression.getOperand();
+      if (operandExpression == null) {
+        throwEvaluateException(DebuggerBundle.message("evaluation.error.unknown.expression.operand", expression.getText()));
+      }
+      
+      operandExpression.accept(this);
+      Evaluator operandEvaluator = myResult;
+
+      // handle unboxing issues
+      final PsiType operandType = operandExpression.getType();
+      @Nullable
+      final PsiType unboxedOperandType = PsiPrimitiveType.getUnboxedType(operandType);
+
+      final IElementType operation = expression.getOperationTokenType();
+
+      if(operation == JavaTokenType.PLUSPLUS || operation == JavaTokenType.MINUSMINUS) {
+        try {
+          final BinaryExpressionEvaluator rightEval = createBinaryEvaluator(
+            operandEvaluator, operandType,
+            new LiteralEvaluator(Integer.valueOf(1), "int"), PsiType.INT,
+            operation == JavaTokenType.PLUSPLUS ? JavaTokenType.PLUS : JavaTokenType.MINUS,
+            unboxedOperandType!= null? unboxedOperandType : operandType
+          );
+          myResult = new AssignmentEvaluator(operandEvaluator, unboxedOperandType != null? new BoxingEvaluator(rightEval) : rightEval);
+        }
+        catch (IncorrectOperationException e) {
+          LOG.error(e);
+        }
+      }
+      else {
+        if (JavaTokenType.PLUS.equals(operation) || JavaTokenType.MINUS.equals(operation)|| JavaTokenType.TILDE.equals(operation)) {
+          operandEvaluator = handleUnaryNumericPromotion(operandType, operandEvaluator);
+        }
+        else {
+          if (unboxedOperandType != null) {
+            operandEvaluator = new UnBoxingEvaluator(operandEvaluator);
+          }
+        }
+        myResult = new UnaryExpressionEvaluator(operation, expressionType.getCanonicalText(), operandEvaluator, expression.getOperationSign().getText());
+      }
+    }
+
+    @Override
+    public void visitMethodCallExpression(PsiMethodCallExpression expression) {
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("visitMethodCallExpression " + expression);
+      }
+      final PsiExpressionList argumentList = expression.getArgumentList();
+      final PsiExpression[] argExpressions = argumentList.getExpressions();
+      List<Evaluator> argumentEvaluators = new ArrayList<Evaluator>(argExpressions.length);
+      // evaluate arguments
+      for (PsiExpression psiExpression : argExpressions) {
+        psiExpression.accept(this);
+        if (myResult == null) {
+          // cannot build evaluator
+          throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", psiExpression.getText()));
+        }
+        argumentEvaluators.add(new DisableGC(myResult));
+      }
+      PsiReferenceExpression methodExpr = expression.getMethodExpression();
+
+      final JavaResolveResult resolveResult = methodExpr.advancedResolve(false);
+      final PsiMethod psiMethod = (PsiMethod)resolveResult.getElement();
+
+      PsiExpression qualifier = methodExpr.getQualifierExpression();
+      Evaluator objectEvaluator;
+      JVMName contextClass = null;
+
+      if(psiMethod != null) {
+        PsiClass methodPsiClass = psiMethod.getContainingClass();
+        contextClass =  JVMNameUtil.getJVMQualifiedName(methodPsiClass);
+        if (psiMethod.hasModifierProperty(PsiModifier.STATIC)) {
+          objectEvaluator = new TypeEvaluator(contextClass);
+        }
+        else if (qualifier != null ) {
+          qualifier.accept(this);
+          objectEvaluator = myResult;
+        }
+        else {
+          int iterationCount = 0;
+          final PsiElement currentFileResolveScope = resolveResult.getCurrentFileResolveScope();
+          if (currentFileResolveScope instanceof PsiClass) {
+            PsiClass aClass = getContextPsiClass();
+            while(aClass != null && !aClass.equals(currentFileResolveScope)) {
+              aClass = getOuterClass(aClass);
+              iterationCount++;
+            }
+          }
+          objectEvaluator = new ThisEvaluator(iterationCount);
+        }
+      }
+      else {
+        //trying to guess
+        if (qualifier != null) {
+          PsiType type = qualifier.getType();
+
+          if (type != null) {
+            contextClass = JVMNameUtil.getJVMQualifiedName(type);
+          }
+
+          if (qualifier instanceof PsiReferenceExpression && ((PsiReferenceExpression)qualifier).resolve() instanceof PsiClass) {
+            // this is a call to a 'static' method
+            if (contextClass == null && type == null) {
+              throwEvaluateException(DebuggerBundle.message("evaluation.error.qualifier.type.unknown", qualifier.getText()));
+            }
+            assert contextClass != null;
+            objectEvaluator = new TypeEvaluator(contextClass);
+          }
+          else {
+            qualifier.accept(this);
+            objectEvaluator = myResult;
+          }
+        }
+        else {
+          objectEvaluator = new ThisEvaluator();
+          contextClass = JVMNameUtil.getContextClassJVMQualifiedName(myPosition);
+          if(contextClass == null && myContextPsiClass != null) {
+            contextClass = JVMNameUtil.getJVMQualifiedName(myContextPsiClass);
+          }
+          //else {
+          //  throw new EvaluateRuntimeException(EvaluateExceptionUtil.createEvaluateException(
+          //    DebuggerBundle.message("evaluation.error.method.not.found", methodExpr.getReferenceName()))
+          //  );
+          //}
+        }
+      }
+
+      if (objectEvaluator == null) {
+        throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText()));
+      }
+
+      if (psiMethod != null && !psiMethod.isConstructor()) {
+        if (psiMethod.getReturnType() == null) {
+          throwEvaluateException(DebuggerBundle.message("evaluation.error.unknown.method.return.type", psiMethod.getText()));
+        }
+      }
+
+      if (psiMethod != null) {
+        // handle autoboxing
+        final PsiParameter[] declaredParams = psiMethod.getParameterList().getParameters();
+        if (declaredParams.length > 0) {
+          final int paramCount = Math.max(declaredParams.length, argExpressions.length);
+          PsiType varargType = null;
+          for (int idx = 0; idx < paramCount; idx++) {
+            if (idx >= argExpressions.length) {
+              break; // actual arguments count is less than number of declared params
+            }
+            PsiType declaredParamType;
+            if (idx < declaredParams.length) {
+              declaredParamType = resolveResult.getSubstitutor().substitute(declaredParams[idx].getType());
+              if (declaredParamType instanceof PsiEllipsisType) {
+                declaredParamType = varargType = ((PsiEllipsisType)declaredParamType).getComponentType();
+              }
+            }
+            else if (varargType != null) {
+              declaredParamType = varargType;
+            }
+            else {
+              break;
+            }
+            final PsiType actualArgType = argExpressions[idx].getType();
+            if (TypeConversionUtil.boxingConversionApplicable(declaredParamType, actualArgType)) {
+              final Evaluator argEval = argumentEvaluators.get(idx);
+              argumentEvaluators.set(idx, declaredParamType instanceof PsiPrimitiveType ? new UnBoxingEvaluator(argEval) : new BoxingEvaluator(argEval));
+            }
+          }
+        }
+      }
+
+      myResult = new MethodEvaluator(objectEvaluator, contextClass, methodExpr.getReferenceName(), psiMethod != null ? JVMNameUtil.getJVMSignature(psiMethod) : null, argumentEvaluators);
+    }
+
+    @Override
+    public void visitLiteralExpression(PsiLiteralExpression expression) {
+      final HighlightInfo parsingError = HighlightUtil.checkLiteralExpressionParsingError(expression);
+      if (parsingError != null) {
+        throwEvaluateException(parsingError.description);
+        return;
+      }
+
+      final PsiType type = expression.getType();
+      if (type == null) {
+        throwEvaluateException(expression + ": null type");
+        return;
+      }
+
+      myResult = new LiteralEvaluator(expression.getValue(), type.getCanonicalText());
+    }
+
+    @Override
+    public void visitArrayAccessExpression(PsiArrayAccessExpression expression) {
+      final PsiExpression indexExpression = expression.getIndexExpression();
+      if(indexExpression == null) {
+        throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText())); return;
+      }
+      indexExpression.accept(this);
+      final Evaluator indexEvaluator = handleUnaryNumericPromotion(indexExpression.getType(), myResult); 
+
+      expression.getArrayExpression().accept(this);
+      Evaluator arrayEvaluator = myResult;
+      myResult = new ArrayAccessEvaluator(arrayEvaluator, indexEvaluator);
+    }
+
+
+    /**
+     * Handles unboxing and numeric promotion issues for
+     * - array diumention expressions
+     * - array index expression
+     * - unary +, -, and ~ operations
+     * @param operandExpressionType
+     * @param operandEvaluator  @return operandEvaluator possibly 'wrapped' with neccesary unboxing and type-casting evaluators to make returning value
+     * sutable for mentioned contexts            
+     */
+    private static Evaluator handleUnaryNumericPromotion(final PsiType operandExpressionType, Evaluator operandEvaluator) {
+      final PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(operandExpressionType);
+      if (unboxedType != null && !PsiType.BOOLEAN.equals(unboxedType)) {
+        operandEvaluator = new UnBoxingEvaluator(operandEvaluator);
+      }
+
+      // handle numeric promotion
+      final PsiType _unboxedIndexType = unboxedType != null? unboxedType : operandExpressionType;
+      if (_unboxedIndexType instanceof PsiPrimitiveType) {
+        final PsiType promotionType = calcUnaryNumericPromotionType((PsiPrimitiveType)_unboxedIndexType);
+        if (promotionType != null) {
+          operandEvaluator = new TypeCastEvaluator(operandEvaluator, promotionType.getCanonicalText(), true);
+        }
+      }
+      return operandEvaluator;
+    }
+
+    @SuppressWarnings({"ConstantConditions"})
+    @Override
+    public void visitTypeCastExpression(PsiTypeCastExpression expression) {
+      final PsiExpression operandExpr = expression.getOperand();
+      operandExpr.accept(this);
+      Evaluator operandEvaluator = myResult;
+      final PsiType castType = expression.getCastType().getType();
+      final PsiType operandType = operandExpr.getType();
+
+      if (castType != null && operandType != null && !TypeConversionUtil.areTypesConvertible(operandType, castType)) {
+        throw new EvaluateRuntimeException(
+          new EvaluateException(JavaErrorMessages.message("inconvertible.type.cast", HighlightUtil.formatType(operandType), HighlightUtil.formatType(castType)))
+        );
+      }
+
+      final boolean shouldPerformBoxingConversion = castType != null && operandType != null && TypeConversionUtil.boxingConversionApplicable(castType, operandType);
+      final boolean castingToPrimitive = castType instanceof PsiPrimitiveType;
+      if (shouldPerformBoxingConversion && castingToPrimitive) {
+        operandEvaluator = new UnBoxingEvaluator(operandEvaluator);
+      }
+
+      final boolean performCastToWrapperClass = shouldPerformBoxingConversion && !castingToPrimitive;
+
+      String castTypeName = castType.getCanonicalText();
+      if (performCastToWrapperClass) {
+        final PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(castType);
+        if (unboxedType != null) {
+          castTypeName = unboxedType.getCanonicalText();
+        }
+      }
+
+      myResult = new TypeCastEvaluator(operandEvaluator, castTypeName, castingToPrimitive);
+      
+      if (performCastToWrapperClass) {
+        myResult = new BoxingEvaluator(myResult);
+      }
+    }
+
+    @Override
+    public void visitClassObjectAccessExpression(PsiClassObjectAccessExpression expression) {
+      PsiType type = expression.getOperand().getType();
+
+      if (type instanceof PsiPrimitiveType) {
+        final JVMName typeName = JVMNameUtil.getJVMRawText(((PsiPrimitiveType)type).getBoxedTypeName());
+        myResult = new FieldEvaluator(new TypeEvaluator(typeName), FieldEvaluator.TargetClassFilter.ALL, "TYPE");
+      }
+      else {
+        myResult = new ClassObjectEvaluator(new TypeEvaluator(JVMNameUtil.getJVMQualifiedName(type)));
+      }
+    }
+
+    @Override
+    public void visitNewExpression(final PsiNewExpression expression) {
+      PsiType expressionPsiType = expression.getType();
+      if (expressionPsiType instanceof PsiArrayType) {
+        Evaluator dimensionEvaluator = null;
+        PsiExpression[] dimensions = expression.getArrayDimensions();
+        if (dimensions.length == 1){
+          PsiExpression dimensionExpression = dimensions[0];
+          dimensionExpression.accept(this);
+          if (myResult != null) {
+            dimensionEvaluator = handleUnaryNumericPromotion(dimensionExpression.getType(), myResult);
+          }
+          else {
+            throwEvaluateException(
+              DebuggerBundle.message("evaluation.error.invalid.array.dimension.expression", dimensionExpression.getText()));
+          }
+        }
+        else if (dimensions.length > 1){
+          throwEvaluateException(DebuggerBundle.message("evaluation.error.multi.dimensional.arrays.creation.not.supported"));
+        }
+
+        Evaluator initializerEvaluator = null;
+        PsiArrayInitializerExpression arrayInitializer = expression.getArrayInitializer();
+        if (arrayInitializer != null) {
+          if (dimensionEvaluator != null) { // initializer already exists
+            throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText()));
+          }
+          arrayInitializer.accept(this);
+          if (myResult != null) {
+            initializerEvaluator = handleUnaryNumericPromotion(arrayInitializer.getType(), myResult);
+          }
+          else {
+            throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", arrayInitializer.getText()));
+          }
+          /*
+          PsiExpression[] initializers = arrayInitializer.getInitializers();
+          initializerEvaluators = new Evaluator[initializers.length];
+          for (int idx = 0; idx < initializers.length; idx++) {
+            PsiExpression initializer = initializers[idx];
+            initializer.accept(this);
+            if (myResult instanceof Evaluator) {
+              initializerEvaluators[idx] = myResult;
+            }
+            else {
+              throw new EvaluateException("Invalid expression for array initializer: " + initializer.getText(), true);
+            }
+          }
+          */
+        }
+        if (dimensionEvaluator == null && initializerEvaluator == null) {
+          throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText()));
+        }
+        myResult = new NewArrayInstanceEvaluator(
+          new TypeEvaluator(JVMNameUtil.getJVMQualifiedName(expressionPsiType)),
+          dimensionEvaluator,
+          initializerEvaluator
+        );
+      }
+      else if (expressionPsiType instanceof PsiClassType){ // must be a class ref
+        PsiClass aClass = ((PsiClassType)expressionPsiType).resolve();
+        if(aClass instanceof PsiAnonymousClass) {
+          throwEvaluateException(DebuggerBundle.message("evaluation.error.anonymous.class.evaluation.not.supported"));
+        }
+        PsiExpressionList argumentList = expression.getArgumentList();
+        if (argumentList == null) {
+          throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText())); return;
+        }
+        PsiExpression[] argExpressions = argumentList.getExpressions();
+        PsiMethod constructor = expression.resolveConstructor();
+        if (constructor == null && argExpressions.length > 0) {
+          throw new EvaluateRuntimeException(new EvaluateException(
+            DebuggerBundle.message("evaluation.error.cannot.resolve.constructor", expression.getText()), null));
+        }
+        Evaluator[] argumentEvaluators = new Evaluator[argExpressions.length];
+        // evaluate arguments
+        for (int idx = 0; idx < argExpressions.length; idx++) {
+          PsiExpression argExpression = argExpressions[idx];
+          argExpression.accept(this);
+          if (myResult != null) {
+            argumentEvaluators[idx] = new DisableGC(myResult);
+          }
+          else {
+            throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", argExpression.getText()));
+          }
+        }
+        //noinspection HardCodedStringLiteral
+        JVMName signature = constructor != null ? JVMNameUtil.getJVMSignature(constructor) : JVMNameUtil.getJVMRawText("()V");
+        myResult = new NewClassInstanceEvaluator(
+          new TypeEvaluator(JVMNameUtil.getJVMQualifiedName(expressionPsiType)),
+          signature,
+          argumentEvaluators
+        );
+      }
+      else {
+        if (expressionPsiType != null) {
+          throwEvaluateException("Unsupported expression type: " + expressionPsiType.getPresentableText());
+        }
+        else {
+          throwEvaluateException("Unknown type for expression: " + expression.getText());
+        }
+      }
+    }
+
+    @Override
+    public void visitArrayInitializerExpression(PsiArrayInitializerExpression expression) {
+      PsiExpression[] initializers = expression.getInitializers();
+      Evaluator[] evaluators = new Evaluator[initializers.length];
+      final PsiType type = expression.getType();
+      boolean primitive = type instanceof PsiArrayType && ((PsiArrayType)type).getComponentType() instanceof PsiPrimitiveType;
+      for (int idx = 0; idx < initializers.length; idx++) {
+        PsiExpression initializer = initializers[idx];
+        initializer.accept(this);
+        if (myResult != null) {
+          final Evaluator coerced =
+            primitive ? handleUnaryNumericPromotion(initializer.getType(), myResult) : new BoxingEvaluator(myResult);
+          evaluators[idx] = new DisableGC(coerced);
+        }
+        else {
+          throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", initializer.getText()));
+        }
+      }
+      myResult = new ArrayInitializerEvaluator(evaluators);
+    }
+
+    @Nullable
+    private static PsiClass getOuterClass(PsiClass aClass) {
+      return aClass == null ? null : PsiTreeUtil.getContextOfType(aClass, PsiClass.class, true);
+    }
+
+    private PsiClass getContainingClass(PsiVariable variable) {
+      PsiElement element = PsiTreeUtil.getParentOfType(variable.getParent(), PsiClass.class, false);
+      return element == null ? getContextPsiClass() : (PsiClass)element;
+    }
+
+    public PsiClass getContextPsiClass() {
+      return myContextPsiClass;
+    }
+
+    protected ExpressionEvaluator buildElement(final PsiElement element) throws EvaluateException {
+      LOG.assertTrue(element.isValid());
+
+      myContextPsiClass = PsiTreeUtil.getContextOfType(element, PsiClass.class, false);
+      try {
+        element.accept(this);
+      }
+      catch (EvaluateRuntimeException e) {
+        throw e.getCause();
+      }
+      if (myResult == null) {
+        throw EvaluateExceptionUtil
+          .createEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", element.toString()));
+      }
+      return new ExpressionEvaluatorImpl(myResult);
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ExpressionEvaluatorImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ExpressionEvaluatorImpl.java
new file mode 100644
index 0000000..4b974c1
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ExpressionEvaluatorImpl.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.engine.evaluation.EvaluationContext;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.openapi.diagnostic.Logger;
+import com.sun.jdi.Value;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: lex
+ * Date: Jul 15, 2003
+ * Time: 1:44:35 PM
+ * To change this template use Options | File Templates.
+ */
+public class ExpressionEvaluatorImpl implements ExpressionEvaluator {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator");
+  Evaluator myEvaluator;
+  Value myValue;
+
+  public ExpressionEvaluatorImpl(Evaluator evaluator) {
+    myEvaluator = evaluator;
+  }
+
+  //call evaluate before
+  public Value getValue() {
+    return myValue;
+  }
+
+  //call evaluate before
+  public Modifier getModifier() {
+    return myEvaluator.getModifier();
+  }
+
+  // EvaluationContextImpl should be at the same stackFrame as it was in the call to EvaluatorBuilderImpl.build
+  public Value evaluate(final EvaluationContext context) throws EvaluateException {
+    if (!context.getDebugProcess().isAttached()) {
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("error.vm.disconnected"));
+    }
+    try {
+      if (context.getFrameProxy() == null) {
+        throw EvaluateExceptionUtil.NULL_STACK_FRAME;
+      }
+
+      Object value = myEvaluator.evaluate((EvaluationContextImpl)context);
+
+      if(value != null && !(value instanceof Value)) {
+        throw EvaluateExceptionUtil
+          .createEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", ""));
+      }
+
+      myValue = (Value) value;
+      return myValue;
+    }
+    catch (Throwable/*IncompatibleThreadStateException*/ e) {
+      if (LOG.isDebugEnabled()) {
+        LOG.debug(e);
+      }
+      if(e instanceof EvaluateException)
+        throw ((EvaluateException)e);
+      else
+        throw EvaluateExceptionUtil.createEvaluateException(e);
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/FieldEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/FieldEvaluator.java
new file mode 100644
index 0000000..4e35754
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/FieldEvaluator.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class FieldEvaluator
+ * @author Jeka
+ */
+package com.intellij.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.JVMNameUtil;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.ui.impl.watch.FieldDescriptorImpl;
+import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiAnonymousClass;
+import com.intellij.psi.PsiArrayType;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiType;
+import com.intellij.psi.util.PsiUtil;
+import com.sun.jdi.*;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.Nullable;
+
+public class FieldEvaluator implements Evaluator {
+  private final Evaluator myObjectEvaluator;
+  private final TargetClassFilter myTargetClassFilter;
+  private final String myFieldName;
+  private Object myEvaluatedQualifier;
+  private Field myEvaluatedField;
+
+  public interface TargetClassFilter {
+    TargetClassFilter ALL = new TargetClassFilter() {
+      public boolean acceptClass(final ReferenceType refType) {
+        return true;
+      }
+    };
+    boolean acceptClass(ReferenceType refType);
+  }
+  
+  public FieldEvaluator(Evaluator objectEvaluator, TargetClassFilter filter, @NonNls String fieldName) {
+    myObjectEvaluator = objectEvaluator;
+    myFieldName = fieldName;
+    myTargetClassFilter = filter;
+  }
+
+  public static TargetClassFilter createClassFilter(PsiType psiType) {
+    if(psiType instanceof PsiArrayType) {
+      return TargetClassFilter.ALL;
+    }
+    PsiClass psiClass = PsiUtil.resolveClassInType(psiType);
+    if (psiClass != null) {
+      return createClassFilter(psiClass);
+    }
+    return new FQNameClassFilter(psiType.getCanonicalText());
+  }
+
+  public static TargetClassFilter createClassFilter(PsiClass psiClass) {
+    if (psiClass instanceof PsiAnonymousClass) {
+      return TargetClassFilter.ALL;
+    }
+    if (PsiUtil.isLocalClass(psiClass)) {
+      return new LocalClassFilter(psiClass.getName());
+    }
+    final String name = JVMNameUtil.getNonAnonymousClassName(psiClass);
+    return name != null? new FQNameClassFilter(name) : TargetClassFilter.ALL;
+  }
+
+  @Nullable
+  private Field findField(Type t, final EvaluationContextImpl context) throws EvaluateException {
+    if(t instanceof ClassType) {
+      ClassType cls = (ClassType) t;
+      if(myTargetClassFilter.acceptClass(cls)) {
+        return cls.fieldByName(myFieldName);
+      }
+      for (final InterfaceType interfaceType : cls.interfaces()) {
+        final Field field = findField(interfaceType, context);
+        if (field != null) {
+          return field;
+        }
+      }
+      return findField(cls.superclass(), context);
+    }
+    else if(t instanceof InterfaceType) {
+      InterfaceType iface = (InterfaceType) t;
+      if(myTargetClassFilter.acceptClass(iface)) {
+        return iface.fieldByName(myFieldName);
+      }
+      for (final InterfaceType interfaceType : iface.superinterfaces()) {
+        final Field field = findField(interfaceType, context);
+        if (field != null) {
+          return field;
+        }
+      }
+    }
+    return null;
+  }
+
+  public Object evaluate(EvaluationContextImpl context) throws EvaluateException {
+    myEvaluatedField = null;
+    myEvaluatedQualifier = null;
+    Object object = myObjectEvaluator.evaluate(context);
+
+    return evaluateField(object, context);
+
+  }
+
+  private Object evaluateField(Object object, EvaluationContextImpl context) throws EvaluateException {
+    if (object instanceof ReferenceType) {
+      ReferenceType refType = (ReferenceType)object;
+      Field field = findField(refType, context);
+      if (field == null || !field.isStatic()) {
+        field = refType.fieldByName(myFieldName);
+      }
+      if (field == null || !field.isStatic()) {
+        throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.no.static.field", myFieldName));
+      }
+      myEvaluatedField = field;
+      myEvaluatedQualifier = refType;
+      return refType.getValue(field);
+    }
+
+    if (object instanceof ObjectReference) {
+      ObjectReference objRef = (ObjectReference)object;
+      ReferenceType refType = objRef.referenceType();
+      if (!(refType instanceof ClassType || refType instanceof ArrayType)) {
+        throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.class.or.array.expected", myFieldName));
+      }
+
+      // expressions like 'array.length' must be treated separately
+      //noinspection HardCodedStringLiteral
+      if (objRef instanceof ArrayReference && "length".equals(myFieldName)) {
+        //noinspection HardCodedStringLiteral
+        return DebuggerUtilsEx.createValue(
+          context.getDebugProcess().getVirtualMachineProxy(),
+          "int",
+          ((ArrayReference)objRef).length()
+        );
+      }
+
+      Field field = findField(refType, context);
+      if (field == null) {
+        field = refType.fieldByName(myFieldName);
+      }
+
+      if (field == null) {
+        throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.no.instance.field", myFieldName));
+      }
+      myEvaluatedQualifier = field.isStatic()? (Object)refType : (Object)objRef;
+      myEvaluatedField = field;
+      return field.isStatic()? refType.getValue(field) : objRef.getValue(field);
+    }
+
+    if(object == null) {
+      throw EvaluateExceptionUtil.createEvaluateException(new NullPointerException());
+    }
+
+    throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.evaluating.field", myFieldName));
+  }
+
+  public Modifier getModifier() {
+    Modifier modifier = null;
+    if (myEvaluatedField != null && (myEvaluatedQualifier instanceof ClassType || myEvaluatedQualifier instanceof ObjectReference)) {
+      modifier = new Modifier() {
+        public boolean canInspect() {
+          return myEvaluatedQualifier instanceof ObjectReference;
+        }
+
+        public boolean canSetValue() {
+          return true;
+        }
+
+        public void setValue(Value value) throws ClassNotLoadedException, InvalidTypeException {
+          if (myEvaluatedQualifier instanceof ReferenceType) {
+            ClassType classType = (ClassType)myEvaluatedQualifier;
+            classType.setValue(myEvaluatedField, value);
+          }
+          else {
+            ObjectReference objRef = (ObjectReference)myEvaluatedQualifier;
+            objRef.setValue(myEvaluatedField, value);
+          }
+        }
+
+        public Type getExpectedType() throws ClassNotLoadedException {
+          return myEvaluatedField.type();
+        }
+
+        public NodeDescriptorImpl getInspectItem(Project project) {
+          if(myEvaluatedQualifier instanceof ObjectReference) {
+            return new FieldDescriptorImpl(project, (ObjectReference)myEvaluatedQualifier, myEvaluatedField);
+          } else
+            return null;
+        }
+      };
+    }
+    return modifier;
+  }
+
+  private static final class FQNameClassFilter implements TargetClassFilter {
+    private final String myQName;
+
+    private FQNameClassFilter(String qName) {
+      myQName = qName;
+    }
+
+    public boolean acceptClass(final ReferenceType refType) {
+      return refType.name().equals(myQName);
+    }
+  }
+
+  private static final class LocalClassFilter implements TargetClassFilter{
+    private final String myLocalClassShortName;
+
+    private LocalClassFilter(String localClassShortName) {
+      myLocalClassShortName = localClassShortName;
+    }
+
+    public boolean acceptClass(final ReferenceType refType) {
+      final String name = refType.name();
+      final int index = name.lastIndexOf(myLocalClassShortName);
+      if (index < 0) {
+        return false;
+      }
+      for (int idx = index - 1; idx >= 0; idx--) {
+        final char ch = name.charAt(idx);
+        if (ch == '$') {
+          return idx < (index - 1);
+        }
+        if (!Character.isDigit(ch)) {
+          return false;
+        }
+      }
+      return false;
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ForStatementEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ForStatementEvaluator.java
new file mode 100644
index 0000000..ff35ef7
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ForStatementEvaluator.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.openapi.util.Comparing;
+import com.sun.jdi.BooleanValue;
+
+/**
+ * @author lex
+ */
+public class ForStatementEvaluator implements Evaluator {
+  private final Evaluator myInitializationEvaluator;
+  private final Evaluator myConditionEvaluator;
+  private final Evaluator myUpdateEvaluator;
+  private final Evaluator myBodyEvaluator;
+
+  private Modifier myModifier;
+  private final String myLabelName;
+
+  public ForStatementEvaluator(Evaluator initializationEvaluator,
+                               Evaluator conditionEvaluator,
+                               Evaluator updateEvaluator,
+                               Evaluator bodyEvaluator,
+                               String labelName) {
+    myInitializationEvaluator = new DisableGC(initializationEvaluator);
+    myConditionEvaluator = new DisableGC(conditionEvaluator);
+    myUpdateEvaluator = new DisableGC(updateEvaluator);
+    myBodyEvaluator = new DisableGC(bodyEvaluator);
+    myLabelName = labelName;
+  }
+
+  public Modifier getModifier() {
+    return myModifier;
+  }
+
+  public Object evaluate(EvaluationContextImpl context) throws EvaluateException {
+    Object value = context.getDebugProcess().getVirtualMachineProxy().mirrorOf();
+    if (myInitializationEvaluator != null) {
+      value = myInitializationEvaluator.evaluate(context);
+      myModifier = myInitializationEvaluator.getModifier();
+    }
+
+    while (true) {
+      if (myConditionEvaluator != null) {
+        value = myConditionEvaluator.evaluate(context);
+        myModifier = myConditionEvaluator.getModifier();
+        if (!(value instanceof BooleanValue)) {
+          throw EvaluateExceptionUtil.BOOLEAN_EXPECTED;
+        }
+        else {
+          if (!((BooleanValue)value).booleanValue()) {
+            break;
+          }
+        }
+      }
+
+      try {
+        myBodyEvaluator.evaluate(context);
+      }
+      catch (BreakException e) {
+        if (Comparing.equal(e.getLabelName(), myLabelName)) {
+          break;
+        }
+        else {
+          throw e;
+        }
+      }
+      catch (ContinueException e) {
+        if (Comparing.equal(e.getLabelName(), myLabelName)) {
+          //continue;
+        }
+        else {
+          throw e;
+        }
+      }
+
+      if (myUpdateEvaluator != null) {
+        value = myUpdateEvaluator.evaluate(context);
+        myModifier = myUpdateEvaluator.getModifier();
+      }
+    }
+
+    return value;
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/IdentityEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/IdentityEvaluator.java
new file mode 100644
index 0000000..4ff1a85
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/IdentityEvaluator.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2000-2010 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.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.sun.jdi.Value;
+
+/**
+* @author Eugene Zhuravlev
+*         Date: Feb 9, 2010
+*/
+public class IdentityEvaluator implements Evaluator {
+  private final Value myValue;
+
+  public IdentityEvaluator(Value value) {
+    myValue = value;
+  }
+
+  public Object evaluate(EvaluationContextImpl context) throws EvaluateException {
+    return myValue;
+  }
+
+  public Modifier getModifier() {
+    return null;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/IfStatementEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/IfStatementEvaluator.java
new file mode 100644
index 0000000..7d518a0
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/IfStatementEvaluator.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.sun.jdi.BooleanValue;
+
+/**
+ * @author lex
+ */
+public class IfStatementEvaluator implements Evaluator {
+  private final Evaluator myConditionEvaluator;
+  private final Evaluator myThenEvaluator;
+  private final Evaluator myElseEvaluator;
+
+  private Modifier myModifier;
+
+  public IfStatementEvaluator(Evaluator conditionEvaluator, Evaluator thenEvaluator, Evaluator elseEvaluator) {
+    myConditionEvaluator = new DisableGC(conditionEvaluator);
+    myThenEvaluator = new DisableGC(thenEvaluator);
+    myElseEvaluator = elseEvaluator == null ? null : new DisableGC(elseEvaluator);
+  }
+
+  public Modifier getModifier() {
+    return myModifier;
+  }
+
+  public Object evaluate(EvaluationContextImpl context) throws EvaluateException {
+    Object value = myConditionEvaluator.evaluate(context);
+    if(!(value instanceof BooleanValue)) {
+      throw EvaluateExceptionUtil.BOOLEAN_EXPECTED;
+    } else {
+      if(((BooleanValue)value).booleanValue()) {
+        value = myThenEvaluator.evaluate(context);
+        myModifier = myThenEvaluator.getModifier();
+      }
+      else {
+        if(myElseEvaluator != null) {
+          value = myElseEvaluator.evaluate(context);
+          myModifier = myElseEvaluator.getModifier();
+        } else {
+          value = context.getDebugProcess().getVirtualMachineProxy().mirrorOf();
+          myModifier = null;
+        }
+      }
+    }
+    return value;
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/InspectArrayItem.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/InspectArrayItem.java
new file mode 100644
index 0000000..0e19e78
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/InspectArrayItem.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.evaluation.expression;
+
+import com.sun.jdi.ArrayReference;
+
+/**
+ * User: lex
+ * Date: Oct 16, 2003
+ * Time: 2:44:38 PM
+ */
+public interface InspectArrayItem extends InspectEntity{
+  ArrayReference getArray    ();
+  int            getItemIndex();
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/InspectEntity.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/InspectEntity.java
new file mode 100644
index 0000000..423ca01
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/InspectEntity.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.evaluation.expression;
+
+/**
+ * User: lex
+ * Date: Oct 15, 2003
+ * Time: 11:38:02 PM
+ */
+public interface InspectEntity {
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/InspectField.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/InspectField.java
new file mode 100644
index 0000000..252fba2
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/InspectField.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.evaluation.expression;
+
+import com.sun.jdi.Field;
+import com.sun.jdi.ObjectReference;
+
+/**
+ * User: lex
+ * Date: Oct 15, 2003
+ * Time: 11:38:25 PM
+ */
+public interface InspectField extends InspectEntity{
+  ObjectReference getObject();
+  Field           getField ();
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/InspectLocal.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/InspectLocal.java
new file mode 100644
index 0000000..79d6b83
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/InspectLocal.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.jdi.StackFrameProxyImpl;
+import com.sun.jdi.LocalVariable;
+
+/**
+ * User: lex
+ * Date: Oct 15, 2003
+ * Time: 11:39:04 PM
+ *
+ * todo [lex] does this interface really required?
+ */
+public interface InspectLocal extends InspectEntity{
+  StackFrameProxyImpl getStackFrame();
+  LocalVariable   getLocal     ();
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/InstanceofEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/InstanceofEvaluator.java
new file mode 100644
index 0000000..2a3c010
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/InstanceofEvaluator.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class InstanceofEvaluator
+ * @author Jeka
+ */
+package com.intellij.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.psi.PsiType;
+import com.sun.jdi.*;
+
+import java.util.LinkedList;
+import java.util.List;
+
+class InstanceofEvaluator implements Evaluator {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.evaluation.expression.InstanceofEvaluator");
+  private final Evaluator myOperandEvaluator;
+  private final TypeEvaluator myTypeEvaluator;
+
+  public InstanceofEvaluator(Evaluator operandEvaluator, TypeEvaluator typeEvaluator) {
+    myOperandEvaluator = operandEvaluator;
+    myTypeEvaluator = typeEvaluator;
+  }
+
+  public Modifier getModifier() {
+    return null;
+  }
+
+  public Object evaluate(EvaluationContextImpl context) throws EvaluateException {
+    Value value = (Value)myOperandEvaluator.evaluate(context);
+    if (value == null) {
+      return DebuggerUtilsEx.createValue(context.getDebugProcess().getVirtualMachineProxy(), PsiType.BOOLEAN.getPresentableText(), false);
+    }
+    if (!(value instanceof ObjectReference)) {
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.object.reference.expected"));
+    }
+    try {
+      ReferenceType refType = (ReferenceType)myTypeEvaluator.evaluate(context);
+      ClassObjectReference classObject = refType.classObject();
+      ClassType classRefType = (ClassType)classObject.referenceType();
+      //noinspection HardCodedStringLiteral
+      Method method = classRefType.concreteMethodByName("isAssignableFrom", "(Ljava/lang/Class;)Z");
+      List args = new LinkedList();
+      args.add(((ObjectReference)value).referenceType().classObject());
+      return context.getDebugProcess().invokeMethod(context, classObject, method, args);
+    }
+    catch (Exception e) {
+      if (LOG.isDebugEnabled()) {
+        LOG.debug(e);
+      }
+      throw EvaluateExceptionUtil.createEvaluateException(e);
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/LiteralEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/LiteralEvaluator.java
new file mode 100644
index 0000000..2f4b85d
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/LiteralEvaluator.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class LiteralEvaluator
+ * @author Jeka
+ */
+package com.intellij.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
+
+class LiteralEvaluator implements Evaluator {
+  private final Object myValue;
+  private final String myExpectedType;
+
+  public LiteralEvaluator(Object value, String expectedType) {
+    myValue = value;
+    myExpectedType = expectedType;
+  }
+
+  public Modifier getModifier() {
+    return null;
+  }
+
+  public Object evaluate(EvaluationContextImpl context) throws EvaluateException {
+    if (myValue == null) {
+      return null;
+    }
+    VirtualMachineProxyImpl vm = context.getDebugProcess().getVirtualMachineProxy();
+    if (myValue instanceof Boolean) {
+      return DebuggerUtilsEx.createValue(vm, myExpectedType, ((Boolean)myValue).booleanValue());
+    }
+    if (myValue instanceof Character) {
+      return DebuggerUtilsEx.createValue(vm, myExpectedType, ((Character)myValue).charValue());
+    }
+    if (myValue instanceof Double) {
+      return DebuggerUtilsEx.createValue(vm, myExpectedType, ((Number)myValue).doubleValue());
+    }
+    if (myValue instanceof Float) {
+      return DebuggerUtilsEx.createValue(vm, myExpectedType, ((Number)myValue).floatValue());
+    }
+    if (myValue instanceof Number) {
+      return DebuggerUtilsEx.createValue(vm, myExpectedType, ((Number)myValue).longValue());
+    }
+    if (myValue instanceof String) {
+      return vm.mirrorOf((String)myValue);
+    }
+    throw EvaluateExceptionUtil
+      .createEvaluateException(DebuggerBundle.message("evaluation.error.unknown.expression.type", myExpectedType));
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/LocalVariableEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/LocalVariableEvaluator.java
new file mode 100644
index 0000000..ce060c0
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/LocalVariableEvaluator.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class LocalVariableEvaluator
+ * @author Jeka
+ */
+package com.intellij.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.jdi.LocalVariableProxyImpl;
+import com.intellij.debugger.jdi.StackFrameProxyImpl;
+import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
+import com.intellij.debugger.ui.impl.watch.LocalVariableDescriptorImpl;
+import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.sun.jdi.*;
+
+import java.util.List;
+
+class LocalVariableEvaluator implements Evaluator {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.evaluation.expression.LocalVariableEvaluator");
+
+  private final String myLocalVariableName;
+  private EvaluationContextImpl myContext;
+  private LocalVariableProxyImpl myEvaluatedVariable;
+  private final boolean myIsJspSpecial;
+  private int myParameterIndex = -1;
+
+  public LocalVariableEvaluator(String localVariableName, boolean isJspSpecial) {
+    myLocalVariableName = localVariableName;
+    myIsJspSpecial = isJspSpecial;
+  }
+
+  public void setParameterIndex(int parameterIndex) {
+    myParameterIndex = parameterIndex;
+  }
+
+  public Object evaluate(EvaluationContextImpl context) throws EvaluateException {
+    StackFrameProxyImpl frameProxy = context.getFrameProxy();
+    if (frameProxy == null) {
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.no.stackframe"));
+    }
+
+    try {
+      ThreadReferenceProxyImpl threadProxy = null;
+      int lastFrameIndex = -1;
+
+      while (true) {
+        try {
+          LocalVariableProxyImpl local = frameProxy.visibleVariableByName(myLocalVariableName);
+          if (local != null) {
+            myEvaluatedVariable = local;
+            myContext = context;
+            return frameProxy.getValue(local);
+          }
+        }
+        catch (EvaluateException e) {
+          if (!(e.getCause() instanceof AbsentInformationException)) {
+            throw e;
+          }
+          if (myParameterIndex < 0) {
+            throw e;
+          }
+          final List<Value> values = frameProxy.getArgumentValues();
+          if (values.isEmpty() || myParameterIndex >= values.size()) {
+            throw e;
+          }
+          return values.get(myParameterIndex);
+        }
+
+        if (myIsJspSpecial) {
+          if (threadProxy == null /* initialize it lazily */) {
+            threadProxy = frameProxy.threadProxy();
+            lastFrameIndex = threadProxy.frameCount() - 1;
+          }
+          final int currentFrameIndex = frameProxy.getFrameIndex();
+          if (currentFrameIndex < lastFrameIndex) {
+            frameProxy = threadProxy.frame(currentFrameIndex + 1);
+            continue;
+          }
+        }
+
+        break;
+      }
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.local.variable.missing", myLocalVariableName));
+    }
+    catch (EvaluateException e) {
+      myEvaluatedVariable = null;
+      myContext = null;
+      throw e;
+    }
+  }
+
+  public Modifier getModifier() {
+    Modifier modifier = null;
+    if (myEvaluatedVariable != null && myContext != null) {
+      modifier = new Modifier() {
+        public boolean canInspect() {
+          return true;
+        }
+
+        public boolean canSetValue() {
+          return true;
+        }
+
+        public void setValue(Value value) throws ClassNotLoadedException, InvalidTypeException {
+          StackFrameProxyImpl frameProxy = myContext.getFrameProxy();
+          try {
+            frameProxy.setValue(myEvaluatedVariable, value);
+          }
+          catch (EvaluateException e) {
+            LOG.error(e);  
+          }
+        }
+
+        public Type getExpectedType() throws ClassNotLoadedException {
+          try {
+            return myEvaluatedVariable.getType();
+          } catch (EvaluateException e) {
+            LOG.error(e);
+            return null;
+          }
+        }
+
+        public NodeDescriptorImpl getInspectItem(Project project) {
+          return new LocalVariableDescriptorImpl(project, myEvaluatedVariable);
+        }
+      };
+    }
+    return modifier;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/MethodEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/MethodEvaluator.java
new file mode 100644
index 0000000..257bad2
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/MethodEvaluator.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class MethodEvaluator
+ * @author Jeka
+ */
+package com.intellij.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.JVMName;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.engine.evaluation.EvaluateRuntimeException;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.openapi.diagnostic.Logger;
+import com.sun.jdi.ClassType;
+import com.sun.jdi.Method;
+import com.sun.jdi.ObjectReference;
+import com.sun.jdi.ReferenceType;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public class MethodEvaluator implements Evaluator {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.evaluation.expression.MethodEvaluator");
+  private final JVMName myClassName;
+  private final JVMName myMethodSignature;
+  private final String myMethodName;
+  private final List myArgumentEvaluators;
+  private final Evaluator myObjectEvaluator;
+
+  public MethodEvaluator(Evaluator objectEvaluator, JVMName className, String methodName, JVMName signature, List argumentEvaluators) {
+    myObjectEvaluator = new DisableGC(objectEvaluator);
+    myClassName = className;
+    myMethodName = methodName;
+    myMethodSignature = signature;
+    myArgumentEvaluators = argumentEvaluators;
+  }
+
+  public Modifier getModifier() {
+    return null;
+  }
+
+  public Object evaluate(EvaluationContextImpl context) throws EvaluateException {
+    if(!context.getDebugProcess().isAttached()) return null;
+    DebugProcessImpl debugProcess = context.getDebugProcess();
+    
+    final boolean requiresSuperObject = 
+      myObjectEvaluator instanceof SuperEvaluator || 
+      (myObjectEvaluator instanceof DisableGC && ((DisableGC)myObjectEvaluator).getDelegate() instanceof SuperEvaluator);
+    
+    final Object object = myObjectEvaluator.evaluate(context);
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("MethodEvaluator: object = " + object);
+    }
+    if(object == null) {
+      throw EvaluateExceptionUtil.createEvaluateException(new NullPointerException());
+    }
+    if (!(object instanceof ObjectReference || object instanceof ClassType)) {
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.evaluating.method", myMethodName));
+    }
+    List args = new ArrayList(myArgumentEvaluators.size());
+    for (Iterator it = myArgumentEvaluators.iterator(); it.hasNext();) {
+      Evaluator evaluator = (Evaluator)it.next();
+      args.add(evaluator.evaluate(context));
+    }
+    try {
+      ReferenceType referenceType = null;
+
+      if(object instanceof ObjectReference) {
+        final ReferenceType qualifierType = ((ObjectReference)object).referenceType();
+        referenceType = debugProcess.findClass(context, qualifierType.name(), qualifierType.classLoader());
+      }
+      else if(object instanceof ClassType) {
+        final ClassType qualifierType = (ClassType)object;
+        referenceType = debugProcess.findClass(context, qualifierType.name(), context.getClassLoader());
+      }
+      else {
+        final String className = myClassName != null? myClassName.getName(debugProcess) : null;
+        if (className != null) {
+          referenceType = debugProcess.findClass(context, className, context.getClassLoader());
+        }
+      }
+      
+      if (referenceType == null) {
+        throw new EvaluateRuntimeException(EvaluateExceptionUtil.createEvaluateException(
+          DebuggerBundle.message("evaluation.error.cannot.evaluate.qualifier", myMethodName))
+        );
+      }
+      final String signature = myMethodSignature != null ? myMethodSignature.getName(debugProcess) : null;
+      final String methodName = DebuggerUtilsEx.methodName(referenceType.name(), myMethodName, signature);
+      if (object instanceof ClassType) {
+        if(referenceType instanceof ClassType) {
+          Method jdiMethod;
+          if(myMethodSignature != null) {
+            jdiMethod = ((ClassType)referenceType).concreteMethodByName(myMethodName, myMethodSignature.getName(debugProcess));
+          }
+          else {
+            List list = referenceType.methodsByName(myMethodName);
+            jdiMethod = (Method)(list.size() > 0 ? list.get(0) : null);
+          }
+          if (jdiMethod != null && jdiMethod.isStatic()) {
+            return debugProcess.invokeMethod(context, (ClassType)referenceType, jdiMethod, args);
+          }
+        }
+        throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.no.static.method", methodName));
+      }
+      // object should be an ObjectReference
+      final ObjectReference objRef = (ObjectReference)object;
+      ReferenceType _refType = referenceType;
+      if (requiresSuperObject && (referenceType instanceof ClassType)) {
+        _refType = ((ClassType)referenceType).superclass();
+      }
+      final Method jdiMethod = DebuggerUtilsEx.findMethod(_refType, myMethodName, signature);
+      if (jdiMethod == null) {
+        throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.no.instance.method", methodName));
+      }
+      if (requiresSuperObject) {
+        return debugProcess.invokeInstanceMethod(context, objRef, jdiMethod, args, ObjectReference.INVOKE_NONVIRTUAL);
+      }
+      return debugProcess.invokeMethod(context, objRef, jdiMethod, args);
+    }
+    catch (Exception e) {
+      if (LOG.isDebugEnabled()) {
+        LOG.debug(e);
+      }
+      throw EvaluateExceptionUtil.createEvaluateException(e);
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/NewArrayInstanceEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/NewArrayInstanceEvaluator.java
new file mode 100644
index 0000000..a0f9033
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/NewArrayInstanceEvaluator.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/**
+ * class NewArrayInstanceEvaluator
+ * created Jun 27, 2001
+ * @author Jeka
+ */
+package com.intellij.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.openapi.diagnostic.Logger;
+import com.sun.jdi.*;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+class NewArrayInstanceEvaluator implements Evaluator {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.evaluation.expression.NewArrayInstanceEvaluator");
+  private final Evaluator myArrayTypeEvaluator;
+  private Evaluator myDimensionEvaluator = null;
+  private Evaluator myInitializerEvaluator = null;
+
+  /**
+   * either dimensionEvaluator or initializerEvaluators must be null!
+   */
+  public NewArrayInstanceEvaluator(Evaluator arrayTypeEvaluator, Evaluator dimensionEvaluator, Evaluator initializerEvaluator) {
+    myArrayTypeEvaluator = arrayTypeEvaluator;
+    myDimensionEvaluator = dimensionEvaluator;
+    myInitializerEvaluator = initializerEvaluator;
+  }
+
+  public Object evaluate(EvaluationContextImpl context) throws EvaluateException {
+//    throw new EvaluateException("Creating new array instances is not supported yet", true);
+    DebugProcessImpl debugProcess = context.getDebugProcess();
+    Object obj = myArrayTypeEvaluator.evaluate(context);
+    if (!(obj instanceof ArrayType)) {
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.array.type.expected"));
+    }
+    ArrayType arrayType = (ArrayType)obj;
+    int dimension;
+    Object[] initialValues = null;
+    if (myDimensionEvaluator != null) {
+      Object o = myDimensionEvaluator.evaluate(context);
+      if (!(o instanceof Value && DebuggerUtilsEx.isNumeric((Value)o))) {
+        throw EvaluateExceptionUtil.createEvaluateException(
+          DebuggerBundle.message("evaluation.error.array.dimention.numeric.value.expected")
+        );
+      }
+      PrimitiveValue value = (PrimitiveValue)o;
+      dimension = value.intValue();
+    }
+    else { // myInitializerEvaluator must not be null
+      Object o = myInitializerEvaluator.evaluate(context);
+      if (!(o instanceof Object[])) {
+        throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.cannot.evaluate.array.initializer"));
+      }
+      initialValues = (Object[])o;
+      dimension = initialValues.length;
+    }
+    ArrayReference arrayReference = debugProcess.newInstance(arrayType, dimension);
+    if (initialValues != null && initialValues.length > 0) {
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("Setting initial values: dimension = "+dimension + "; array size is "+initialValues.length);
+      }
+      setInitialValues(arrayReference, initialValues, context);
+    }
+    return arrayReference;
+  }
+
+  private static void setInitialValues(ArrayReference arrayReference, Object[] values, EvaluationContextImpl context) throws EvaluateException {
+    ArrayType type = (ArrayType)arrayReference.referenceType();
+    DebugProcessImpl debugProcess = context.getDebugProcess();
+    try {
+      if (type.componentType() instanceof ArrayType) {
+        ArrayType componentType = (ArrayType)type.componentType();
+        int length = arrayReference.length();
+        for (int idx = 0; idx < length; idx++) {
+          ArrayReference componentArray = (ArrayReference)arrayReference.getValue(idx);
+          Object[] componentArrayValues = (Object[])values[idx];
+          if (componentArray == null) {
+            componentArray = debugProcess.newInstance(componentType, componentArrayValues.length);
+            arrayReference.setValue(idx, componentArray);
+          }
+          setInitialValues(componentArray, componentArrayValues, context);
+        }
+      }
+      else {
+        if (values.length > 0) {
+          arrayReference.setValues(new ArrayList(Arrays.asList(values)));
+        }
+      }
+    }
+    catch (ClassNotLoadedException ex) {
+      final ReferenceType referenceType;
+      try {
+        referenceType = context.isAutoLoadClasses()? debugProcess.loadClass(context, ex.className(), type.classLoader()) : null;
+      }
+      catch (InvocationException e) {
+        throw EvaluateExceptionUtil.createEvaluateException(e);
+      }
+      catch (ClassNotLoadedException e) {
+        throw EvaluateExceptionUtil.createEvaluateException(e);
+      }
+      catch (IncompatibleThreadStateException e) {
+        throw EvaluateExceptionUtil.createEvaluateException(e);
+      }
+      catch (InvalidTypeException e) {
+        throw EvaluateExceptionUtil.createEvaluateException(e);
+      }
+      if (referenceType != null) {
+        setInitialValues(arrayReference, values, context);
+      }
+      else {
+        throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("error.class.not.loaded", ex.className()));
+      }
+    }
+    catch (InvalidTypeException ex) {
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.incompatible.array.initializer.type"));
+    }
+    catch (IndexOutOfBoundsException ex) {
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.invalid.array.size"));
+    }
+    catch (ClassCastException ex) {
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.cannot.initialize.array"));
+    }
+  }
+
+  public Modifier getModifier() {
+    return null;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/NewClassInstanceEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/NewClassInstanceEvaluator.java
new file mode 100644
index 0000000..c3e7f81
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/NewClassInstanceEvaluator.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/**
+ * class NewArrayInstanceEvaluator
+ * created Jun 27, 2001
+ * @author Jeka
+ */
+package com.intellij.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.JVMName;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.DebuggerBundle;
+import com.sun.jdi.ClassType;
+import com.sun.jdi.Method;
+import com.sun.jdi.ObjectReference;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+class NewClassInstanceEvaluator implements Evaluator {
+  private final Evaluator myClassTypeEvaluator;
+  private final JVMName myConstructorSignature;
+  private final Evaluator[] myParamsEvaluators;
+
+  public NewClassInstanceEvaluator(Evaluator classTypeEvaluator, JVMName constructorSignature, Evaluator[] argumentEvaluators) {
+    myClassTypeEvaluator = classTypeEvaluator;
+    myConstructorSignature = constructorSignature;
+    myParamsEvaluators = argumentEvaluators;
+  }
+
+  public Object evaluate(EvaluationContextImpl context) throws EvaluateException {
+    DebugProcessImpl debugProcess = context.getDebugProcess();
+    Object obj = myClassTypeEvaluator.evaluate(context);
+    if (!(obj instanceof ClassType)) {
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.cannot.evaluate.class.type"));
+    }
+    ClassType classType = (ClassType)obj;
+    // find constructor
+    Method method = DebuggerUtilsEx.findMethod(classType, "<init>", myConstructorSignature.getName(debugProcess));
+    if (method == null) {
+      throw EvaluateExceptionUtil.createEvaluateException(
+        DebuggerBundle.message("evaluation.error.cannot.resolve.constructor", myConstructorSignature.getDisplayName(debugProcess)));
+    }
+    // evaluate arguments
+    List<Object> arguments;
+    if (myParamsEvaluators != null) {
+      arguments = new ArrayList<Object>(myParamsEvaluators.length);
+      for (Evaluator evaluator : myParamsEvaluators) {
+        arguments.add(evaluator.evaluate(context));
+      }
+    }
+    else {
+      arguments = Collections.emptyList();
+    }
+    ObjectReference objRef;
+    try {
+      objRef = debugProcess.newInstance(context, classType, method, arguments);
+    }
+    catch (EvaluateException e) {
+      throw EvaluateExceptionUtil.createEvaluateException(e);
+    }
+    return objRef;
+  }
+
+  public Modifier getModifier() {
+    return null;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/PostfixOperationEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/PostfixOperationEvaluator.java
new file mode 100644
index 0000000..203256c
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/PostfixOperationEvaluator.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+
+public class PostfixOperationEvaluator implements Evaluator{
+  private final Evaluator myOperandEvaluator;
+
+  private final Evaluator myIncrementImpl;
+
+  private Modifier myModifier;
+
+  public PostfixOperationEvaluator(Evaluator operandEvaluator, Evaluator incrementImpl) {
+    myOperandEvaluator = new DisableGC(operandEvaluator);
+    myIncrementImpl = new DisableGC(incrementImpl);
+  }
+
+  public Object evaluate(EvaluationContextImpl context) throws EvaluateException {
+    final Object value = myOperandEvaluator.evaluate(context);
+    myModifier = myOperandEvaluator.getModifier();
+    Object operationResult = myIncrementImpl.evaluate(context);
+    AssignmentEvaluator.assign(myModifier, operationResult, context);
+    return value;
+  }
+
+  public Modifier getModifier() {
+    return myModifier;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/SuperEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/SuperEvaluator.java
new file mode 100644
index 0000000..ba126ae
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/SuperEvaluator.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.evaluation.expression;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: Jan 22, 2007
+ */
+public class SuperEvaluator extends ThisEvaluator{
+
+  public SuperEvaluator(final int iterations) {
+    super(iterations);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/SyntheticVariableEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/SyntheticVariableEvaluator.java
new file mode 100644
index 0000000..e96884c
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/SyntheticVariableEvaluator.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.sun.jdi.Type;
+import com.sun.jdi.Value;
+
+/**
+ * @author lex
+ */
+public class SyntheticVariableEvaluator implements Evaluator{
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.evaluation.expression.SyntheticVariableEvaluator");
+
+  private final CodeFragmentEvaluator myCodeFragmentEvaluator;
+  private final String myLocalName;
+
+  public SyntheticVariableEvaluator(CodeFragmentEvaluator codeFragmentEvaluator, String localName) {
+    myCodeFragmentEvaluator = codeFragmentEvaluator;
+    myLocalName = localName;
+  }
+
+  public Object evaluate(EvaluationContextImpl context) throws EvaluateException {
+    return myCodeFragmentEvaluator.getValue(myLocalName, context.getDebugProcess().getVirtualMachineProxy());
+  }
+
+  public Modifier getModifier() {
+    return new Modifier() {
+      public boolean canInspect() {
+        return false;
+      }
+
+      public boolean canSetValue() {
+        return false;
+      }
+
+      public void setValue(Value value) throws EvaluateException {
+        myCodeFragmentEvaluator.setValue(myLocalName, value);
+      }
+
+      public Type getExpectedType() {
+        LOG.assertTrue(false);
+        return null;
+      }
+
+      public NodeDescriptorImpl getInspectItem(Project project) {
+        return null;
+      }
+    };
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ThisEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ThisEvaluator.java
new file mode 100644
index 0000000..c9e26c3
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ThisEvaluator.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class ThisEvaluator
+ * @author Jeka
+ */
+package com.intellij.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.sun.jdi.Field;
+import com.sun.jdi.ObjectReference;
+import com.sun.jdi.Value;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+
+public class ThisEvaluator implements Evaluator {
+  private final int myIterations;
+
+  public ThisEvaluator() {
+    myIterations = 0;
+  }
+
+  public ThisEvaluator(int iterations) {
+    myIterations = iterations;
+  }
+
+  public Modifier getModifier() {
+    return null;
+  }
+
+  public Object evaluate(EvaluationContextImpl context) throws EvaluateException {
+    Value objRef = context.getThisObject();
+    if(myIterations > 0) {
+      ObjectReference thisRef = (ObjectReference)objRef;
+      for (int idx = 0; idx < myIterations && thisRef != null; idx++) {
+        thisRef  = getOuterObject(thisRef);
+      }
+      objRef = thisRef;
+    }
+    if(objRef == null) {
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.this.not.avalilable"));
+    }
+    return objRef;
+  }
+
+  @Nullable
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  private static ObjectReference getOuterObject(ObjectReference objRef) {
+    if (objRef == null) {
+      return null;
+    }
+    List<Field> list = objRef.referenceType().fields();
+    for (final Field field : list) {
+      final String name = field.name();
+      if (name != null && name.startsWith("this$")) {
+        final ObjectReference rv = (ObjectReference)objRef.getValue(field);
+        if (rv != null) {
+          return rv;
+        }
+      }
+    }
+    return null;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/TypeCastEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/TypeCastEvaluator.java
new file mode 100644
index 0000000..482373d
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/TypeCastEvaluator.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class TypeCastEvaluator
+ * @author Jeka
+ */
+package com.intellij.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
+import com.sun.jdi.BooleanValue;
+import com.sun.jdi.CharValue;
+import com.sun.jdi.PrimitiveValue;
+import com.sun.jdi.Value;
+
+public class TypeCastEvaluator implements Evaluator {
+  private final Evaluator myOperandEvaluator;
+  private final String myCastType;
+  private final boolean myIsPrimitive;
+
+  public TypeCastEvaluator(Evaluator operandEvaluator, String castType, boolean isPrimitive) {
+    myOperandEvaluator = operandEvaluator;
+    myCastType = castType;
+    myIsPrimitive = isPrimitive;
+  }
+
+  public Modifier getModifier() {
+    return null;
+  }
+
+  public Object evaluate(EvaluationContextImpl context) throws EvaluateException {
+    Value value = (Value)myOperandEvaluator.evaluate(context);
+    if (value == null) {
+      if (myIsPrimitive) {
+        throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.cannot.cast.null", myCastType));
+      }
+      return null;
+    }
+    VirtualMachineProxyImpl vm = context.getDebugProcess().getVirtualMachineProxy();
+    if (DebuggerUtilsEx.isInteger(value)) {
+      value = DebuggerUtilsEx.createValue(vm, myCastType, ((PrimitiveValue)value).longValue());
+      if (value == null) {
+        throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.cannot.cast.numeric", myCastType));
+      }
+    }
+    else if (DebuggerUtilsEx.isNumeric(value)) {
+      value = DebuggerUtilsEx.createValue(vm, myCastType, ((PrimitiveValue)value).doubleValue());
+      if (value == null) {
+        throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.cannot.cast.numeric", myCastType));
+      }
+    }
+    else if (value instanceof BooleanValue) {
+      value = DebuggerUtilsEx.createValue(vm, myCastType, ((BooleanValue)value).booleanValue());
+      if (value == null) {
+        throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.cannot.cast.boolean", myCastType));
+      }
+    }
+    else if (value instanceof CharValue) {
+      value = DebuggerUtilsEx.createValue(vm, myCastType, ((CharValue)value).charValue());
+      if (value == null) {
+        throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.cannot.cast.char", myCastType));
+      }
+    }
+    return value;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/TypeEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/TypeEvaluator.java
new file mode 100644
index 0000000..1ba0457
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/TypeEvaluator.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class TypeEvaluator
+ * @author Jeka
+ */
+package com.intellij.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.JVMName;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.sun.jdi.ReferenceType;
+
+public class TypeEvaluator implements Evaluator {
+  private final JVMName myTypeName;
+
+  public TypeEvaluator(JVMName typeName) {
+    myTypeName = typeName;
+  }
+
+  public Modifier getModifier() {
+    return null;
+  }
+
+  /**
+   * @return ReferenceType in the target VM, with the given fully qualified name
+   */
+  public Object evaluate(EvaluationContextImpl context) throws EvaluateException {
+    DebugProcessImpl debugProcess = context.getDebugProcess();
+    String typeName = myTypeName.getName(debugProcess);
+    final ReferenceType type = debugProcess.findClass(context, typeName, context.getClassLoader());
+    if (type == null) {
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("error.class.not.loaded", typeName));
+    }
+    return type;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/UnBoxingEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/UnBoxingEvaluator.java
new file mode 100644
index 0000000..cb4505b
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/UnBoxingEvaluator.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2000-2010 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.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.openapi.util.Pair;
+import com.intellij.util.containers.HashMap;
+import com.sun.jdi.ClassType;
+import com.sun.jdi.Method;
+import com.sun.jdi.ObjectReference;
+import com.sun.jdi.Value;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: Feb 8, 2010
+ */
+public class UnBoxingEvaluator implements Evaluator{
+  private final Evaluator myOperand;
+  private static final Map<String, Pair<String, String>> TYPES_TO_CONVERSION_METHOD_MAP = new HashMap<String, Pair<String, String>>();
+  static {
+    TYPES_TO_CONVERSION_METHOD_MAP.put("java.lang.Boolean", new Pair<String, String>("booleanValue", "()Z"));
+    TYPES_TO_CONVERSION_METHOD_MAP.put("java.lang.Byte", new Pair<String, String>("byteValue", "()B"));
+    TYPES_TO_CONVERSION_METHOD_MAP.put("java.lang.Character", new Pair<String, String>("charValue", "()C"));
+    TYPES_TO_CONVERSION_METHOD_MAP.put("java.lang.Short", new Pair<String, String>("shortValue", "()S"));
+    TYPES_TO_CONVERSION_METHOD_MAP.put("java.lang.Integer", new Pair<String, String>("intValue", "()I"));
+    TYPES_TO_CONVERSION_METHOD_MAP.put("java.lang.Long", new Pair<String, String>("longValue", "()J"));
+    TYPES_TO_CONVERSION_METHOD_MAP.put("java.lang.Float", new Pair<String, String>("floatValue", "()F"));
+    TYPES_TO_CONVERSION_METHOD_MAP.put("java.lang.Double", new Pair<String, String>("doubleValue", "()D"));
+  }
+
+  public static boolean isTypeUnboxable(String typeName) {
+    return TYPES_TO_CONVERSION_METHOD_MAP.containsKey(typeName);
+  }
+
+  public UnBoxingEvaluator(Evaluator operand) {
+    myOperand = new DisableGC(operand);
+  }
+
+  public Object evaluate(EvaluationContextImpl context) throws EvaluateException {
+    final Value result = (Value)myOperand.evaluate(context);
+    if (result == null) {
+      throw new EvaluateException("java.lang.NullPointerException: cannot unbox null value");
+    }
+    if (result instanceof ObjectReference) {
+      final String valueTypeName = result.type().name();
+      final Pair<String, String> pair = TYPES_TO_CONVERSION_METHOD_MAP.get(valueTypeName);
+      if (pair != null) {
+        return convertToPrimitive(context, (ObjectReference)result, pair.getFirst(), pair.getSecond());
+      }
+    }
+    return result;
+  }
+                                          
+  @Nullable
+  public Modifier getModifier() {
+    return null;
+  }
+
+  private static Value convertToPrimitive(EvaluationContextImpl context, ObjectReference value, final String conversionMethodName,
+                                          String conversionMethodSignature) throws EvaluateException {
+    final DebugProcessImpl process = context.getDebugProcess();
+    final ClassType wrapperClass = (ClassType)value.referenceType();
+    final List<Method> methods = wrapperClass.methodsByName(conversionMethodName, conversionMethodSignature);
+    if (methods.size() == 0) { 
+      throw new EvaluateException("Cannot convert to primitive value of type " + value.type() + ": Unable to find method " +
+                                  conversionMethodName + conversionMethodSignature);
+    }
+
+    final Method method = methods.get(0);
+
+    return process.invokeMethod(context, value, method, new ArrayList());
+  }
+}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/UnaryExpressionEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/UnaryExpressionEvaluator.java
new file mode 100644
index 0000000..77f3c34
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/UnaryExpressionEvaluator.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class UnaryExpressionEvaluator
+ * @author Jeka
+ */
+package com.intellij.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
+import com.intellij.psi.JavaTokenType;
+import com.intellij.psi.tree.IElementType;
+import com.sun.jdi.BooleanValue;
+import com.sun.jdi.PrimitiveValue;
+import com.sun.jdi.Value;
+
+class UnaryExpressionEvaluator implements Evaluator {
+  private final IElementType myOperationType;
+  private final String myExpectedType;
+  private final Evaluator myOperandEvaluator;
+  private final String myOperationText;
+
+  public UnaryExpressionEvaluator(IElementType operationType, String expectedType, Evaluator operandEvaluator, final String operationText) {
+    myOperationType = operationType;
+    myExpectedType = expectedType;
+    myOperandEvaluator = operandEvaluator;
+    myOperationText = operationText;
+  }
+
+  public Modifier getModifier() {
+    return null;
+  }
+
+  public Object evaluate(EvaluationContextImpl context) throws EvaluateException {
+    Value operand = (Value)myOperandEvaluator.evaluate(context);
+    VirtualMachineProxyImpl vm = context.getDebugProcess().getVirtualMachineProxy();
+    if (myOperationType == JavaTokenType.PLUS) {
+      if (DebuggerUtilsEx.isNumeric(operand)) {
+        return operand;
+      }
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.numeric.expected"));
+    }
+    else if (myOperationType == JavaTokenType.MINUS) {
+      if (DebuggerUtilsEx.isInteger(operand)) {
+        long v = ((PrimitiveValue)operand).longValue();
+        return DebuggerUtilsEx.createValue(vm, myExpectedType, -v);
+      }
+      if (DebuggerUtilsEx.isNumeric(operand)) {
+        double v = ((PrimitiveValue)operand).doubleValue();
+        return DebuggerUtilsEx.createValue(vm, myExpectedType, -v);
+      }
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.numeric.expected"));
+    }
+    else if (myOperationType == JavaTokenType.TILDE) {
+      if (DebuggerUtilsEx.isInteger(operand)) {
+        long v = ((PrimitiveValue)operand).longValue();
+        return DebuggerUtilsEx.createValue(vm, myExpectedType, ~v);
+      }
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.integer.expected"));
+    }
+    else if (myOperationType == JavaTokenType.EXCL) {
+      if (operand instanceof BooleanValue) {
+        boolean v = ((BooleanValue)operand).booleanValue();
+        return DebuggerUtilsEx.createValue(vm, myExpectedType, !v);
+      }
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.boolean.expected"));
+    }
+    
+    throw EvaluateExceptionUtil.createEvaluateException(
+      DebuggerBundle.message("evaluation.error.operation.not.supported", myOperationText)
+    );
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/WhileStatementEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/WhileStatementEvaluator.java
new file mode 100644
index 0000000..82f4ca8
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/WhileStatementEvaluator.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.openapi.util.Comparing;
+import com.sun.jdi.BooleanValue;
+
+/**
+ * @author lex
+ */
+public class WhileStatementEvaluator implements Evaluator {
+  private final Evaluator myConditionEvaluator;
+  private final Evaluator myBodyEvaluator;
+  private final String myLabelName;
+
+  public WhileStatementEvaluator(Evaluator conditionEvaluator, Evaluator bodyEvaluator, String labelName) {
+    myConditionEvaluator = new DisableGC(conditionEvaluator);
+    myBodyEvaluator = new DisableGC(bodyEvaluator);
+    myLabelName = labelName;
+  }
+
+  public Modifier getModifier() {
+    return myConditionEvaluator.getModifier();
+  }
+
+  public Object evaluate(EvaluationContextImpl context) throws EvaluateException {
+    Object value;
+    while (true) {
+      value = myConditionEvaluator.evaluate(context);
+      if (!(value instanceof BooleanValue)) {
+        throw EvaluateExceptionUtil.BOOLEAN_EXPECTED;
+      }
+      else {
+        if (!((BooleanValue)value).booleanValue()) {
+          break;
+        }
+      }
+      try {
+        myBodyEvaluator.evaluate(context);
+      }
+      catch (BreakException e) {
+        if (Comparing.equal(e.getLabelName(), myLabelName)) {
+          break;
+        }
+        else {
+          throw e;
+        }
+      }
+      catch (ContinueException e) {
+        if (!Comparing.equal(e.getLabelName(), myLabelName)) {
+          throw e;
+        }
+      }
+    }
+
+    return value;
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/events/DebuggerCommandImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/events/DebuggerCommandImpl.java
new file mode 100644
index 0000000..038ff6d
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/events/DebuggerCommandImpl.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.events;
+
+import com.intellij.debugger.impl.DebuggerTaskImpl;
+
+/**
+ * @author lex
+ */
+public abstract class DebuggerCommandImpl extends DebuggerTaskImpl {
+  protected abstract void action() throws Exception;
+
+  protected void commandCancelled() {
+  }
+
+  public Priority getPriority() {
+    return Priority.LOW;
+  }
+
+  public final void notifyCancelled() {
+    try {
+      commandCancelled();
+    }
+    finally {
+      release();
+    }
+  }
+
+  public final void run() throws Exception{
+    try {
+      action();
+    }
+    finally {
+      release();
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/events/DebuggerContextCommandImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/events/DebuggerContextCommandImpl.java
new file mode 100644
index 0000000..aaf3631
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/events/DebuggerContextCommandImpl.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.events;
+
+import com.intellij.debugger.engine.SuspendContextImpl;
+import com.intellij.debugger.engine.SuspendManager;
+import com.intellij.debugger.engine.SuspendManagerUtil;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
+import com.intellij.openapi.diagnostic.Logger;
+import com.sun.jdi.ObjectCollectedException;
+
+public abstract class DebuggerContextCommandImpl extends SuspendContextCommandImpl {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.events.DebuggerContextCommandImpl");
+
+  private final DebuggerContextImpl myDebuggerContext;
+
+  protected DebuggerContextCommandImpl(DebuggerContextImpl debuggerContext) {
+    super(debuggerContext.getSuspendContext());
+    myDebuggerContext = debuggerContext;
+  }
+
+  public final DebuggerContextImpl getDebuggerContext() {
+    return myDebuggerContext;
+  }
+
+  public final void contextAction() throws Exception {
+    final SuspendManager suspendManager = myDebuggerContext.getDebugProcess().getSuspendManager();
+
+    final ThreadReferenceProxyImpl debuggerContextThread = myDebuggerContext.getThreadProxy();
+    final boolean isSuspendedByContext;
+    try {
+      isSuspendedByContext = suspendManager.isSuspended(debuggerContextThread);
+    }
+    catch (ObjectCollectedException e) {
+      notifyCancelled();
+      return;
+    }
+    if (isSuspendedByContext) {
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("Context thread " + getSuspendContext().getThread());
+        LOG.debug("Debug thread" + debuggerContextThread);
+      }
+      threadAction();
+    }
+    else {
+      // there are no suspend context currently registered
+      SuspendContextImpl suspendContextForThread = SuspendManagerUtil.findContextByThread(suspendManager, debuggerContextThread);
+      if(suspendContextForThread != null) {
+        suspendContextForThread.postponeCommand(this);
+      }
+      else {
+        notifyCancelled();
+      }
+    }
+  }
+
+  abstract public void threadAction ();
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/events/SuspendContextCommandImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/events/SuspendContextCommandImpl.java
new file mode 100644
index 0000000..f3ad395
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/events/SuspendContextCommandImpl.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.events;
+
+import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
+import com.intellij.debugger.engine.SuspendContextImpl;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.util.containers.Stack;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: lex
+ * Date: Feb 24, 2004
+ * Time: 7:01:31 PM
+ * Performs contextAction when evaluation is available in suspend context
+ */
+public abstract class SuspendContextCommandImpl extends DebuggerCommandImpl {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.SuspendContextCommand");
+  private final SuspendContextImpl mySuspendContext;
+
+  protected SuspendContextCommandImpl(SuspendContextImpl suspendContext) {
+    mySuspendContext = suspendContext;
+  }
+
+  public abstract void contextAction() throws Exception;
+
+  public final void action() throws Exception {
+    if(LOG.isDebugEnabled()) {
+      LOG.debug("trying " + this);
+    }
+
+    final SuspendContextImpl suspendContext = getSuspendContext();
+
+    if (suspendContext == null) {
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("skip processing - context is null " + this);
+      }
+      notifyCancelled();
+      return;
+    }
+
+    if(suspendContext.myInProgress) {
+      suspendContext.postponeCommand(this);
+    }
+    else {
+      try {
+        if(!suspendContext.isResumed()) {
+          suspendContext.myInProgress = true;
+          contextAction();
+        }
+        else {
+          notifyCancelled();
+        }
+      }
+      finally{
+        suspendContext.myInProgress = false;
+        SuspendContextCommandImpl postponed = suspendContext.pollPostponedCommand();
+        if (postponed != null) {
+          final Stack<SuspendContextCommandImpl> stack = new Stack<SuspendContextCommandImpl>();
+          while (postponed != null) {
+            stack.push(postponed);
+            postponed = suspendContext.pollPostponedCommand();
+          }
+          final DebuggerManagerThreadImpl managerThread = suspendContext.getDebugProcess().getManagerThread();
+          while (!stack.isEmpty()) {
+            managerThread.pushBack(stack.pop());
+          }
+        }
+      }
+    }
+  }
+
+  public SuspendContextImpl getSuspendContext() {
+    return mySuspendContext;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/requests/LocatableEventRequestor.java b/java/debugger/impl/src/com/intellij/debugger/engine/requests/LocatableEventRequestor.java
new file mode 100644
index 0000000..db64d1d
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/requests/LocatableEventRequestor.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.requests;
+
+import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
+import com.intellij.debugger.requests.Requestor;
+import com.sun.jdi.event.LocatableEvent;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: lex
+ * Date: Jun 27, 2003
+ * Time: 8:05:52 PM
+ * To change this template use Options | File Templates.
+ */
+public interface LocatableEventRequestor extends Requestor {
+  /**
+   * @returns true if requesto was hit by the event, false otherwise
+   */ 
+  boolean processLocatableEvent(SuspendContextCommandImpl action, LocatableEvent event) throws EventProcessingException;
+
+  /**
+   * @return either DebuggerSettings.SUSPEND_NONE or DebuggerSettings.SUSPEND_ALL or DebuggerSettings.SUSPEND_THREAD
+   */
+  String getSuspendPolicy();
+
+  class EventProcessingException extends Exception {
+    private final String myTitle;
+
+    public EventProcessingException(String title, String message, Throwable cause) {
+      super(message, cause);
+      myTitle = title;
+    }
+
+    public String getTitle() {
+      return myTitle;
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/requests/MethodReturnValueWatcher.java b/java/debugger/impl/src/com/intellij/debugger/engine/requests/MethodReturnValueWatcher.java
new file mode 100644
index 0000000..d56c31e
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/requests/MethodReturnValueWatcher.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.requests;
+
+import com.intellij.debugger.settings.DebuggerSettings;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.util.ArrayUtil;
+import com.sun.jdi.Method;
+import com.sun.jdi.ObjectCollectedException;
+import com.sun.jdi.ThreadReference;
+import com.sun.jdi.Value;
+import com.sun.jdi.event.MethodExitEvent;
+import com.sun.jdi.request.EventRequest;
+import com.sun.jdi.request.EventRequestManager;
+import com.sun.jdi.request.MethodExitRequest;
+import org.jetbrains.annotations.Nullable;
+
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: Nov 23, 2006
+ */
+public class MethodReturnValueWatcher  {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.requests.MethodReturnValueWatcher");
+  private @Nullable Method myLastExecutedMethod;
+  private @Nullable Value myLastMethodReturnValue;
+  private @Nullable MethodExitRequest myRequest;
+  private java.lang.reflect.Method myReturnValueMethod;
+  private volatile boolean myEnabled;
+  private boolean myFeatureEnabled;
+  private final EventRequestManager myRequestManager;
+
+  public MethodReturnValueWatcher(EventRequestManager requestManager) {
+    myRequestManager = requestManager;
+    myFeatureEnabled = DebuggerSettings.getInstance().WATCH_RETURN_VALUES;
+  }
+
+  public boolean processMethodExitEvent(MethodExitEvent event) {
+    if (event.request() != myRequest) {
+      return false;
+    }
+    try {
+      final Method method = event.method();
+      //myLastMethodReturnValue = event.returnValue();
+      try {
+        if (myReturnValueMethod == null) {
+          //noinspection HardCodedStringLiteral
+          myReturnValueMethod = MethodExitEvent.class.getDeclaredMethod("returnValue", ArrayUtil.EMPTY_CLASS_ARRAY);
+        }
+        final Value retVal = (Value)myReturnValueMethod.invoke(event);
+        
+        if (method == null || !"void".equals(method.returnTypeName())) {
+          // remember methods with non-void return types only
+          myLastExecutedMethod = method;
+          myLastMethodReturnValue = retVal;
+        }
+      }
+      catch (NoSuchMethodException ignored) {
+      }
+      catch (IllegalAccessException ignored) {
+      }
+      catch (InvocationTargetException ignored) {
+      }
+    }
+    catch (UnsupportedOperationException ex) {
+      LOG.error(ex);
+    }
+    return true;
+  }
+
+
+  @Nullable
+  public Method getLastExecutedMethod() {
+    return myLastExecutedMethod;
+  }
+
+  @Nullable
+  public Value getLastMethodReturnValue() {
+    return myLastMethodReturnValue;
+  }
+
+  public boolean isFeatureEnabled() {
+    return myFeatureEnabled;
+  }
+
+  public boolean isEnabled() {
+    return myEnabled;
+  }
+
+  public void setFeatureEnabled(final boolean featureEnabled) {
+    myFeatureEnabled = featureEnabled;
+    myLastExecutedMethod = null;
+    myLastMethodReturnValue = null;
+  }
+
+  public void enable(ThreadReference thread) {
+    setTrackingEnabled(true, thread);
+  }
+  
+  public void disable() {
+    setTrackingEnabled(false, null);
+  }
+  
+  private void setTrackingEnabled(boolean trackingEnabled, final ThreadReference thread) {
+    myEnabled = trackingEnabled;
+    updateRequestState(trackingEnabled && myFeatureEnabled, thread);
+  }
+
+  private void updateRequestState(final boolean enabled, @Nullable final ThreadReference thread) {
+    try {
+      final MethodExitRequest request = myRequest;
+      if (request != null) {
+        myRequest = null;
+        myRequestManager.deleteEventRequest(request);
+      }
+      if (enabled) {
+        myLastExecutedMethod = null;
+        myLastMethodReturnValue = null;
+        myRequest = createRequest(thread);
+        myRequest.enable();
+      }
+    }
+    catch (ObjectCollectedException ignored) {
+    }
+  }
+  
+  private MethodExitRequest createRequest(@Nullable final ThreadReference thread) {
+    final MethodExitRequest request = myRequestManager.createMethodExitRequest();
+    request.setSuspendPolicy(EventRequest.SUSPEND_NONE);
+    if (thread != null) {
+      request.addThreadFilter(thread);
+    }
+    return request;
+  }
+  
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/requests/RequestManagerImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/requests/RequestManagerImpl.java
new file mode 100644
index 0000000..9d10487
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/requests/RequestManagerImpl.java
@@ -0,0 +1,471 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.requests;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.SourcePosition;
+import com.intellij.debugger.engine.*;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.events.DebuggerCommandImpl;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.requests.ClassPrepareRequestor;
+import com.intellij.debugger.requests.RequestManager;
+import com.intellij.debugger.requests.Requestor;
+import com.intellij.debugger.settings.DebuggerSettings;
+import com.intellij.debugger.ui.breakpoints.Breakpoint;
+import com.intellij.debugger.ui.breakpoints.BreakpointManager;
+import com.intellij.debugger.ui.breakpoints.FilteredRequestor;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Computable;
+import com.intellij.openapi.util.Key;
+import com.intellij.psi.PsiClass;
+import com.intellij.ui.classFilter.ClassFilter;
+import com.intellij.util.containers.HashMap;
+import com.sun.jdi.*;
+import com.sun.jdi.event.ClassPrepareEvent;
+import com.sun.jdi.request.*;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author lex
+ * Date: May 6, 2003
+ * Time: 5:32:38 PM
+ */
+public class RequestManagerImpl extends DebugProcessAdapterImpl implements RequestManager {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.RequestManagerImpl");
+
+  private static final Key CLASS_NAME = Key.create("ClassName");
+  private static final Key<Requestor> REQUESTOR = Key.create("Requestor");
+
+  private final DebugProcessImpl myDebugProcess;
+  private final Map<Requestor, String> myRequestWarnings = new HashMap<Requestor, String>();
+
+  private final Map<Requestor, Set<EventRequest>> myRequestorToBelongedRequests = new HashMap<Requestor, Set<EventRequest>>();
+  private EventRequestManager myEventRequestManager;
+  private @Nullable ThreadReference myFilterThread;
+
+  public RequestManagerImpl(DebugProcessImpl debugProcess) {
+    myDebugProcess = debugProcess;
+    myDebugProcess.addDebugProcessListener(this);
+  }
+
+
+  public EventRequestManager getVMRequestManager() {
+    return myEventRequestManager;
+  }
+
+  @Nullable
+  public ThreadReference getFilterThread() {
+    return myFilterThread;
+  }
+
+  public void setFilterThread(@Nullable final ThreadReference filterThread) {
+    myFilterThread = filterThread;
+  }
+
+  public Set<EventRequest> findRequests(Requestor requestor) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    final Set<EventRequest> requestSet = myRequestorToBelongedRequests.get(requestor);
+    if (requestSet == null) {
+      return Collections.emptySet();
+    }
+    return Collections.unmodifiableSet(requestSet);
+  }
+
+  public Requestor findRequestor(EventRequest request) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    return request != null? (Requestor)request.getProperty(REQUESTOR) : null;
+  }
+
+  private static void addClassFilter(EventRequest request, String pattern){
+    if(request instanceof AccessWatchpointRequest){
+      ((AccessWatchpointRequest) request).addClassFilter(pattern);
+    }
+    else if(request instanceof ExceptionRequest){
+      ((ExceptionRequest) request).addClassFilter(pattern);
+    }
+    else if(request instanceof MethodEntryRequest) {
+      ((MethodEntryRequest)request).addClassFilter(pattern);
+    }
+    else if(request instanceof MethodExitRequest) {
+      ((MethodExitRequest)request).addClassFilter(pattern);
+    }
+    else if(request instanceof ModificationWatchpointRequest) {
+      ((ModificationWatchpointRequest)request).addClassFilter(pattern);
+    }
+    else if(request instanceof WatchpointRequest) {
+      ((WatchpointRequest)request).addClassFilter(pattern);
+    }
+  }
+
+  private static void addClassExclusionFilter(EventRequest request, String pattern){
+    if(request instanceof AccessWatchpointRequest){
+      ((AccessWatchpointRequest) request).addClassExclusionFilter(pattern);
+    }
+    else if(request instanceof ExceptionRequest){
+      ((ExceptionRequest) request).addClassExclusionFilter(pattern);
+    }
+    else if(request instanceof MethodEntryRequest) {
+      ((MethodEntryRequest)request).addClassExclusionFilter(pattern);
+    }
+    else if(request instanceof MethodExitRequest) {
+      ((MethodExitRequest)request).addClassExclusionFilter(pattern);
+    }
+    else if(request instanceof ModificationWatchpointRequest) {
+      ((ModificationWatchpointRequest)request).addClassExclusionFilter(pattern);
+    }
+    else if(request instanceof WatchpointRequest) {
+      ((WatchpointRequest)request).addClassExclusionFilter(pattern);
+    }
+  }
+
+  private void addLocatableRequest(FilteredRequestor requestor, EventRequest request) {
+    if(DebuggerSettings.SUSPEND_ALL.equals(requestor.SUSPEND_POLICY)) {
+      request.setSuspendPolicy(EventRequest.SUSPEND_ALL);
+    }
+    else {
+      //when requestor.SUSPEND_POLICY == SUSPEND_NONE
+      //we should pause thread in order to evaluate conditions
+      request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
+    }
+
+    if (requestor.COUNT_FILTER_ENABLED && requestor.COUNT_FILTER > 0) {
+      request.addCountFilter(requestor.COUNT_FILTER);
+    }
+
+    if (requestor.CLASS_FILTERS_ENABLED && !(request instanceof BreakpointRequest) /*no built-in class filters support for breakpoint requests*/ ) {
+      ClassFilter[] classFilters = requestor.getClassFilters();
+      for (final ClassFilter filter : classFilters) {
+        if (!filter.isEnabled()) {
+          continue;
+        }
+        final JVMName jvmClassName = ApplicationManager.getApplication().runReadAction(new Computable<JVMName>() {
+          public JVMName compute() {
+            PsiClass psiClass =
+              DebuggerUtilsEx.findClass(filter.getPattern(), myDebugProcess.getProject(), myDebugProcess.getSearchScope());
+            if (psiClass == null) {
+              return null;
+            }
+            return JVMNameUtil.getJVMQualifiedName(psiClass);
+          }
+        });
+        String pattern = filter.getPattern();
+        try {
+          if (jvmClassName != null) {
+            pattern = jvmClassName.getName(myDebugProcess);
+          }
+        }
+        catch (EvaluateException e) {
+        }
+
+        addClassFilter(request, pattern);
+      }
+
+      final ClassFilter[] iclassFilters = requestor.getClassExclusionFilters();
+      for (ClassFilter filter : iclassFilters) {
+        if (filter.isEnabled()) {
+          addClassExclusionFilter(request, filter.getPattern());
+        }
+      }
+    }
+
+    registerRequestInternal(requestor, request);
+  }
+
+  public void registerRequestInternal(final Requestor requestor, final EventRequest request) {
+    registerRequest(requestor, request);
+    request.putProperty(REQUESTOR, requestor);
+  }
+
+  private void registerRequest(Requestor requestor, EventRequest request) {
+    Set<EventRequest> reqSet = myRequestorToBelongedRequests.get(requestor);
+    if(reqSet == null) {
+      reqSet = new HashSet<EventRequest>();
+      myRequestorToBelongedRequests.put(requestor, reqSet);
+    }
+    reqSet.add(request);
+
+  }
+
+  // requests creation
+  public ClassPrepareRequest createClassPrepareRequest(ClassPrepareRequestor requestor, String pattern) {
+    ClassPrepareRequest classPrepareRequest = myEventRequestManager.createClassPrepareRequest();
+    classPrepareRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
+    classPrepareRequest.addClassFilter(pattern);
+    classPrepareRequest.putProperty(CLASS_NAME, pattern);
+
+    registerRequestInternal(requestor, classPrepareRequest);
+    return classPrepareRequest;
+  }
+
+  public ExceptionRequest createExceptionRequest(FilteredRequestor requestor, ReferenceType referenceType, boolean notifyCaught, boolean notifyUnCaught) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    ExceptionRequest req = myEventRequestManager.createExceptionRequest(referenceType, notifyCaught, notifyUnCaught);
+    addLocatableRequest(requestor, req);
+    return req;
+  }
+
+  public MethodEntryRequest createMethodEntryRequest(FilteredRequestor requestor) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    MethodEntryRequest req = myEventRequestManager.createMethodEntryRequest();
+    addLocatableRequest(requestor, req);
+    return req;
+  }
+
+  public MethodExitRequest createMethodExitRequest(FilteredRequestor requestor) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    MethodExitRequest req = myEventRequestManager.createMethodExitRequest();
+    addLocatableRequest(requestor, req);
+    return req;
+  }
+
+  public BreakpointRequest createBreakpointRequest(FilteredRequestor requestor, Location location) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    BreakpointRequest req = myEventRequestManager.createBreakpointRequest(location);
+    addLocatableRequest(requestor, req);
+    myRequestWarnings.remove(requestor);
+    return req;
+  }
+
+  public AccessWatchpointRequest createAccessWatchpointRequest(FilteredRequestor requestor, Field field) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    AccessWatchpointRequest req = myEventRequestManager.createAccessWatchpointRequest(field);
+    addLocatableRequest(requestor, req);
+    return req;
+  }
+
+  public ModificationWatchpointRequest createModificationWatchpointRequest(FilteredRequestor requestor, Field field) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    ModificationWatchpointRequest req = myEventRequestManager.createModificationWatchpointRequest(field);
+    addLocatableRequest(requestor, req);
+    return req;
+  }
+
+  public void deleteRequest(Requestor requestor) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    if(!myDebugProcess.isAttached()) {
+      return;
+    }
+    final Set<EventRequest> requests = myRequestorToBelongedRequests.remove(requestor);
+    if(requests == null) {
+      return;
+    }
+    for (final EventRequest request : requests) {
+      try {
+        final Requestor targetRequestor = (Requestor)request.getProperty(REQUESTOR);
+        if (targetRequestor != requestor) {
+          // the same request may be assigned to more than one requestor, but
+          // there is only one 'targetRequestor' for each request, so if target requestor and requestor being processed are different,
+          // should clear also the mapping targetRequestor->request
+          final Set<EventRequest> allTargetRequestorRequests = myRequestorToBelongedRequests.get(targetRequestor);
+          if (allTargetRequestorRequests != null) {
+            allTargetRequestorRequests.remove(request);
+            if (allTargetRequestorRequests.size() == 0) {
+              myRequestorToBelongedRequests.remove(targetRequestor);
+            }
+          }
+        }
+        myEventRequestManager.deleteEventRequest(request);
+      }
+      catch (InvalidRequestStateException ignored) {
+        // request is already deleted
+      }
+      catch (InternalException e) {
+        if (e.errorCode() == 41) {
+          //event request not found
+          //there could be no requests after hotswap
+        }
+        else {
+          LOG.error(e);
+        }
+      }
+    }
+  }
+
+  public void callbackOnPrepareClasses(final ClassPrepareRequestor requestor, final SourcePosition classPosition) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    ClassPrepareRequest prepareRequest = myDebugProcess.getPositionManager().createPrepareRequest(requestor, classPosition);
+
+    if(prepareRequest == null) {
+      setInvalid(requestor, DebuggerBundle.message("status.invalid.breakpoint.out.of.class"));
+      return;
+    }
+
+    registerRequest(requestor, prepareRequest);
+    prepareRequest.enable();
+  }
+
+  public void callbackOnPrepareClasses(ClassPrepareRequestor requestor, String classOrPatternToBeLoaded) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    ClassPrepareRequest classPrepareRequest = createClassPrepareRequest(requestor, classOrPatternToBeLoaded);
+
+    registerRequest(requestor, classPrepareRequest);
+    classPrepareRequest.enable();
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("classOrPatternToBeLoaded = " + classOrPatternToBeLoaded);
+    }
+  }
+
+  public void enableRequest(EventRequest request) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    LOG.assertTrue(findRequestor(request) != null);
+    try {
+      final ThreadReference filterThread = myFilterThread;
+      if (filterThread != null) {
+        if (request instanceof BreakpointRequest) {
+          ((BreakpointRequest)request).addThreadFilter(filterThread);
+        }
+        else if (request instanceof MethodEntryRequest) {
+          ((MethodEntryRequest)request).addThreadFilter(filterThread);
+        }
+        else if (request instanceof MethodExitRequest) {
+          ((MethodExitRequest)request).addThreadFilter(filterThread);
+        }
+      }
+      request.enable();
+    } catch (InternalException e) {
+      if(e.errorCode() == 41) {
+        //event request not found
+        //there could be no requests after hotswap
+      } else {
+        LOG.error(e);
+      }
+    }
+  }
+
+  public void setInvalid(Requestor requestor, String message) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    //deleteRequest(requestor);
+    //myRequestorToBelongedRequests.remove(requestor); // clear any mapping to empty set if any
+    if (!isVerified(requestor)) {
+      myRequestWarnings.put(requestor, message);
+    }
+  }
+  
+  public @Nullable String getWarning(Requestor requestor) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    return myRequestWarnings.get(requestor);
+  }
+
+  public boolean isVerified(Requestor requestor) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    for (EventRequest request : findRequests(requestor)) {
+      /*ClassPrepareRequest is added in any case, so do not count it*/
+      if (!(request instanceof ClassPrepareRequest)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  public void processDetached(DebugProcessImpl process, boolean closedByUser) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    myEventRequestManager = null;
+    myRequestWarnings.clear();
+    myRequestorToBelongedRequests.clear();
+  }
+
+  public void processAttached(DebugProcessImpl process) {
+    myEventRequestManager = myDebugProcess.getVirtualMachineProxy().eventRequestManager();
+    // invoke later, so that requests are for sure created only _after_ 'processAttached()' methods of other listeneres are executed
+    process.getManagerThread().schedule(new DebuggerCommandImpl() {
+      protected void action() throws Exception {
+        final BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(myDebugProcess.getProject()).getBreakpointManager();
+        for (final Breakpoint breakpoint : breakpointManager.getBreakpoints()) {
+          breakpoint.createRequest(myDebugProcess);
+        }
+      }
+    });
+  }
+
+  public void processClassPrepared(final ClassPrepareEvent event) {
+    if (!myDebugProcess.isAttached()) {
+      return;
+    }
+
+    final ReferenceType refType = event.referenceType();
+
+    if (refType instanceof ClassType || refType instanceof InterfaceType) {
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("signature = " + refType.signature());
+      }
+      ClassPrepareRequestor requestor = (ClassPrepareRequestor)event.request().getProperty(REQUESTOR);
+      if (requestor != null) {
+        if (LOG.isDebugEnabled()) {
+          LOG.debug("requestor found " + refType.signature());
+        }
+        requestor.processClassPrepare(myDebugProcess, refType);
+      }
+    }
+  }
+
+  private static interface AllProcessesCommand {
+    void action(DebugProcessImpl process);
+  }
+
+  private static void invoke(Project project, final AllProcessesCommand command) {
+    for (DebuggerSession debuggerSession : (DebuggerManagerEx.getInstanceEx(project)).getSessions()) {
+      final DebugProcessImpl process = debuggerSession.getProcess();
+      if (process != null) {
+        process.getManagerThread().invoke(new DebuggerCommandImpl() {
+          protected void action() throws Exception {
+            command.action(process);
+          }
+        });
+      }
+    }
+  }
+
+  public static void createRequests(final Breakpoint breakpoint) {
+    invoke(breakpoint.getProject(), new AllProcessesCommand (){
+      public void action(DebugProcessImpl process)  {
+        breakpoint.createRequest(process);
+      }
+    });
+  }
+
+  public static void updateRequests(final Breakpoint breakpoint) {
+    invoke(breakpoint.getProject(), new AllProcessesCommand (){
+      public void action(DebugProcessImpl process)  {
+        process.getRequestsManager().myRequestWarnings.remove(breakpoint);
+        process.getRequestsManager().deleteRequest(breakpoint);
+        breakpoint.createRequest(process);
+      }
+    });
+  }
+
+  public static void deleteRequests(final Breakpoint breakpoint) {
+    invoke(breakpoint.getProject(), new AllProcessesCommand (){
+      public void action(DebugProcessImpl process)  {
+        process.getRequestsManager().myRequestWarnings.remove(breakpoint);
+        process.getRequestsManager().deleteRequest(breakpoint);
+      }
+    });
+  }
+
+  public void clearWarnings() {
+    myRequestWarnings.clear();
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerContextImpl.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerContextImpl.java
new file mode 100644
index 0000000..5762517
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerContextImpl.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Interface DebuggerContextImpl
+ * @author Jeka
+ */
+package com.intellij.debugger.impl;
+
+import com.intellij.debugger.DebuggerContext;
+import com.intellij.debugger.SourcePosition;
+import com.intellij.debugger.engine.ContextUtil;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
+import com.intellij.debugger.engine.SuspendContextImpl;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.jdi.StackFrameProxyImpl;
+import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiElement;
+import com.sun.jdi.ObjectReference;
+import com.sun.jdi.Value;
+import org.jetbrains.annotations.Nullable;
+
+
+public final class DebuggerContextImpl implements DebuggerContext {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.impl.DebuggerContextImpl");
+
+  public static final DebuggerContextImpl EMPTY_CONTEXT = DebuggerContextImpl.createDebuggerContext((DebuggerSession) null, null, null, null);
+
+  private boolean myInitialized;
+
+  private final DebuggerSession      myDebuggerSession;
+  private final DebugProcessImpl     myDebugProcess;
+  private final SuspendContextImpl   mySuspendContext;
+  private final ThreadReferenceProxyImpl myThreadProxy;
+
+  private       StackFrameProxyImpl  myFrameProxy;
+  private       SourcePosition       mySourcePosition;
+  private       PsiElement           myContextElement;
+
+  private DebuggerContextImpl(DebuggerSession session, DebugProcessImpl debugProcess, SuspendContextImpl context, ThreadReferenceProxyImpl threadProxy, StackFrameProxyImpl frameProxy, SourcePosition position, PsiElement contextElement, boolean initialized) {
+    LOG.assertTrue(frameProxy == null || threadProxy == null || threadProxy == frameProxy.threadProxy());
+    LOG.assertTrue(debugProcess == null ? frameProxy == null && threadProxy == null : true);
+    myDebuggerSession = session;
+    myThreadProxy = threadProxy;
+    myFrameProxy = frameProxy;
+    myDebugProcess = debugProcess;
+    mySourcePosition = position;
+    mySuspendContext = context;
+    myContextElement = contextElement;
+    myInitialized = initialized;
+  }
+
+  public DebuggerSession getDebuggerSession() {
+    return myDebuggerSession;
+  }
+
+  public DebugProcessImpl getDebugProcess() {
+    return myDebugProcess;
+  }
+
+  public ThreadReferenceProxyImpl getThreadProxy() {
+    return myThreadProxy;
+  }
+
+  public SuspendContextImpl getSuspendContext() {
+    return mySuspendContext;
+  }
+
+  public Project getProject() {
+    return myDebugProcess != null ? myDebugProcess.getProject() : null;
+  }
+
+  @Nullable
+  public StackFrameProxyImpl getFrameProxy() {
+    LOG.assertTrue(myInitialized);
+    return myFrameProxy;
+  }
+
+  public SourcePosition getSourcePosition() {
+    LOG.assertTrue(myInitialized);
+    return mySourcePosition;
+  }
+
+  public PsiElement getContextElement() {
+    LOG.assertTrue(myInitialized);
+    PsiElement contextElement = myContextElement;
+    if(contextElement != null && !contextElement.isValid()) {
+      myContextElement = ContextUtil.getContextElement(mySourcePosition);
+    }
+    return myContextElement;
+  }
+
+  public EvaluationContextImpl createEvaluationContext(Value thisObject) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    return new EvaluationContextImpl(getSuspendContext(), getFrameProxy(), thisObject);
+  }
+
+  public EvaluationContextImpl createEvaluationContext() {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    StackFrameProxyImpl frameProxy = getFrameProxy();
+    ObjectReference objectReference;
+    try {
+      objectReference = frameProxy != null ? frameProxy.thisObject() : null;
+    }
+    catch (EvaluateException e) {
+      LOG.info(e);
+      objectReference = null;
+    }
+    return new EvaluationContextImpl(getSuspendContext(), frameProxy, objectReference);
+  }
+
+  public static DebuggerContextImpl createDebuggerContext(DebuggerSession session, SuspendContextImpl context, ThreadReferenceProxyImpl threadProxy, StackFrameProxyImpl frameProxy) {
+    LOG.assertTrue(frameProxy == null || threadProxy == null || threadProxy == frameProxy.threadProxy());
+    LOG.assertTrue(session == null || session.getProcess() != null);
+    return new DebuggerContextImpl(session, session != null ? session.getProcess() : null, context, threadProxy, frameProxy, null, null, context == null);
+  }
+
+  public void initCaches() {
+    if(myInitialized) return;
+
+    myInitialized = true;
+    if(myFrameProxy == null) {
+      if(myThreadProxy != null) {
+        try {
+          myFrameProxy = myThreadProxy.frameCount() > 0 ? myThreadProxy.frame(0) : null;
+        }
+        catch (EvaluateException e) {
+        }
+      }
+    }
+
+    if(myFrameProxy != null) {
+      PsiDocumentManager.getInstance(getProject()).commitAndRunReadAction(new Runnable() {
+        public void run() {
+          if (mySourcePosition == null) {
+            mySourcePosition = ContextUtil.getSourcePosition(DebuggerContextImpl.this);
+          }
+          myContextElement = ContextUtil.getContextElement(mySourcePosition);
+        }
+      });
+    }
+  }
+
+  public void setPositionCache(SourcePosition position) {
+    LOG.assertTrue(!myInitialized, "Debugger context is initialized. Cannot change caches");
+    mySourcePosition = position;
+  }
+
+  public boolean isInitialised() {
+    return myInitialized;
+  }
+
+  public boolean isEvaluationPossible() {
+    return getDebugProcess().getSuspendManager().getPausedContext() != null;
+  }
+}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerContextListener.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerContextListener.java
new file mode 100644
index 0000000..395a2af
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerContextListener.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl;
+import java.util.EventListener;
+
+
+public interface DebuggerContextListener extends EventListener{
+  void changeEvent(DebuggerContextImpl newContext, int event);
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerContextUtil.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerContextUtil.java
new file mode 100644
index 0000000..a117e74
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerContextUtil.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl;
+
+import com.intellij.debugger.engine.SuspendContextImpl;
+import com.intellij.debugger.jdi.StackFrameProxyImpl;
+import com.intellij.debugger.ui.impl.watch.ThreadDescriptorImpl;
+import com.intellij.openapi.application.ApplicationManager;
+import org.jetbrains.annotations.NotNull;
+
+public class DebuggerContextUtil {
+  public static void setStackFrame(DebuggerStateManager manager, final StackFrameProxyImpl stackFrame) {
+    ApplicationManager.getApplication().assertIsDispatchThread();
+    DebuggerContextImpl context = manager.getContext();
+    if(context == null) return;
+
+    DebuggerContextImpl newContext = DebuggerContextImpl.createDebuggerContext(context.getDebuggerSession(), context.getSuspendContext(), stackFrame.threadProxy(), stackFrame);
+
+    manager.setState(newContext, context.getDebuggerSession().getState(), DebuggerSession.EVENT_REFRESH, null);
+  }
+
+  public static void setThread(DebuggerStateManager contextManager, ThreadDescriptorImpl item) {
+    ApplicationManager.getApplication().assertIsDispatchThread();
+    DebuggerContextImpl context = contextManager.getContext();
+
+    DebuggerContextImpl newContext = DebuggerContextImpl.createDebuggerContext(context.getDebuggerSession(), item.getSuspendContext(), item.getThreadReference(), null);
+
+    contextManager.setState(newContext, context.getDebuggerSession().getState(), DebuggerSession.EVENT_CONTEXT, null);
+  }
+
+  public static DebuggerContextImpl createDebuggerContext(@NotNull DebuggerSession session, SuspendContextImpl suspendContext){
+    return DebuggerContextImpl.createDebuggerContext(session, suspendContext, suspendContext != null ? suspendContext.getThread() : null, null);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerManagerAdapter.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerManagerAdapter.java
new file mode 100644
index 0000000..6fe296e
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerManagerAdapter.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2000-2012 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.debugger.impl;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: 1/30/12
+ */
+public class DebuggerManagerAdapter implements DebuggerManagerListener{
+  @Override
+  public void sessionCreated(DebuggerSession session) {
+  }
+
+  @Override
+  public void sessionAttached(DebuggerSession session) {
+  }
+
+  @Override
+  public void sessionDetached(DebuggerSession session) {
+  }
+
+  @Override
+  public void sessionRemoved(DebuggerSession session) {
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerManagerImpl.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerManagerImpl.java
new file mode 100644
index 0000000..bf78d82
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerManagerImpl.java
@@ -0,0 +1,594 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl;
+
+import com.intellij.debugger.*;
+import com.intellij.debugger.apiAdapters.TransportServiceWrapper;
+import com.intellij.debugger.engine.*;
+import com.intellij.debugger.settings.DebuggerSettings;
+import com.intellij.debugger.ui.GetJPDADialog;
+import com.intellij.debugger.ui.breakpoints.BreakpointManager;
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.ExecutionResult;
+import com.intellij.execution.Executor;
+import com.intellij.execution.configurations.JavaParameters;
+import com.intellij.execution.configurations.ModuleRunProfile;
+import com.intellij.execution.configurations.RemoteConnection;
+import com.intellij.execution.configurations.RunProfileState;
+import com.intellij.execution.process.ProcessAdapter;
+import com.intellij.execution.process.ProcessEvent;
+import com.intellij.execution.process.ProcessHandler;
+import com.intellij.execution.runners.ProgramRunner;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.colors.EditorColorsListener;
+import com.intellij.openapi.editor.colors.EditorColorsManager;
+import com.intellij.openapi.editor.colors.EditorColorsScheme;
+import com.intellij.openapi.extensions.Extensions;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.projectRoots.JavaSdk;
+import com.intellij.openapi.projectRoots.JavaSdkVersion;
+import com.intellij.openapi.projectRoots.JdkUtil;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.projectRoots.ex.JavaSdkUtil;
+import com.intellij.openapi.startup.StartupManager;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.SystemInfo;
+import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiClass;
+import com.intellij.util.EventDispatcher;
+import com.intellij.util.Function;
+import com.intellij.util.containers.ContainerUtil;
+import org.jdom.Element;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.File;
+import java.util.*;
+import java.util.jar.Attributes;
+
+public class DebuggerManagerImpl extends DebuggerManagerEx {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.impl.DebuggerManagerImpl");
+  private final Project myProject;
+  private final HashMap<ProcessHandler, DebuggerSession> mySessions = new HashMap<ProcessHandler, DebuggerSession>();
+  private final BreakpointManager myBreakpointManager;
+  private final List<NameMapper> myNameMappers = ContainerUtil.createEmptyCOWList();
+  private final List<Function<DebugProcess, PositionManager>> myCustomPositionManagerFactories =
+    new ArrayList<Function<DebugProcess, PositionManager>>();
+
+  private final EventDispatcher<DebuggerManagerListener> myDispatcher = EventDispatcher.create(DebuggerManagerListener.class);
+  private final MyDebuggerStateManager myDebuggerStateManager = new MyDebuggerStateManager();
+
+  private final DebuggerContextListener mySessionListener = new DebuggerContextListener() {
+    public void changeEvent(DebuggerContextImpl newContext, int event) {
+
+      final DebuggerSession session = newContext.getDebuggerSession();
+      if (event == DebuggerSession.EVENT_PAUSE && myDebuggerStateManager.myDebuggerSession != session) {
+        // if paused in non-active session; switch current session
+        myDebuggerStateManager.setState(newContext, session.getState(), event, null);
+        return;
+      }
+
+      if (myDebuggerStateManager.myDebuggerSession == session) {
+        myDebuggerStateManager.fireStateChanged(newContext, event);
+      }
+      if (event == DebuggerSession.EVENT_ATTACHED) {
+        myDispatcher.getMulticaster().sessionAttached(session);
+      }
+      else if (event == DebuggerSession.EVENT_DETACHED) {
+        myDispatcher.getMulticaster().sessionDetached(session);
+      }
+      else if (event == DebuggerSession.EVENT_DISPOSE) {
+        dispose(session);
+        if (myDebuggerStateManager.myDebuggerSession == session) {
+          myDebuggerStateManager
+            .setState(DebuggerContextImpl.EMPTY_CONTEXT, DebuggerSession.STATE_DISPOSED, DebuggerSession.EVENT_DISPOSE, null);
+        }
+      }
+    }
+  };
+  @NonNls private static final String DEBUG_KEY_NAME = "idea.xdebug.key";
+
+  public void addClassNameMapper(final NameMapper mapper) {
+    myNameMappers.add(mapper);
+  }
+
+  public void removeClassNameMapper(final NameMapper mapper) {
+    myNameMappers.remove(mapper);
+  }
+
+  public String getVMClassQualifiedName(@NotNull final PsiClass aClass) {
+    for (NameMapper nameMapper : myNameMappers) {
+      final String qName = nameMapper.getQualifiedName(aClass);
+      if (qName != null) {
+        return qName;
+      }
+    }
+    return aClass.getQualifiedName();
+  }
+
+  public void addDebuggerManagerListener(DebuggerManagerListener listener) {
+    myDispatcher.addListener(listener);
+  }
+
+  public void removeDebuggerManagerListener(DebuggerManagerListener listener) {
+    myDispatcher.removeListener(listener);
+  }
+
+  public DebuggerManagerImpl(Project project, StartupManager startupManager, final EditorColorsManager colorsManager) {
+    myProject = project;
+    myBreakpointManager = new BreakpointManager(myProject, startupManager, this);
+    final EditorColorsListener myColorsListener = new EditorColorsListener() {
+      public void globalSchemeChange(EditorColorsScheme scheme) {
+        getBreakpointManager().updateBreakpointsUI();
+      }
+    };
+    colorsManager.addEditorColorsListener(myColorsListener);
+    Disposer.register(project, new Disposable() {
+      public void dispose() {
+        colorsManager.removeEditorColorsListener(myColorsListener);
+      }
+    });
+  }
+
+  public DebuggerSession getSession(DebugProcess process) {
+    ApplicationManager.getApplication().assertIsDispatchThread();
+    for (final DebuggerSession debuggerSession : getSessions()) {
+      if (process == debuggerSession.getProcess()) return debuggerSession;
+    }
+    return null;
+  }
+
+  public Collection<DebuggerSession> getSessions() {
+    synchronized (mySessions) {
+      final Collection<DebuggerSession> values = mySessions.values();
+      return values.isEmpty() ? Collections.<DebuggerSession>emptyList() : new ArrayList<DebuggerSession>(values);
+    }
+  }
+
+  public void disposeComponent() {
+  }
+
+  public void initComponent() {
+  }
+
+  public void projectClosed() {
+  }
+
+  public void projectOpened() {
+    myBreakpointManager.init();
+  }
+
+  public void readExternal(Element element) throws InvalidDataException {
+    myBreakpointManager.readExternal(element);
+  }
+
+  public void writeExternal(Element element) throws WriteExternalException {
+    myBreakpointManager.writeExternal(element);
+  }
+
+
+  public DebuggerSession attachVirtualMachine(Executor executor,
+                                              ProgramRunner runner,
+                                              ModuleRunProfile profile,
+                                              RunProfileState state,
+                                              RemoteConnection remoteConnection,
+                                              boolean pollConnection
+  ) throws ExecutionException {
+    return attachVirtualMachine(new DefaultDebugEnvironment(myProject,
+                                                            executor,
+                                                            runner,
+                                                            profile,
+                                                            state,
+                                                            remoteConnection,
+                                                            pollConnection));
+  }
+
+  public DebuggerSession attachVirtualMachine(DebugEnvironment environment) throws ExecutionException {
+    ApplicationManager.getApplication().assertIsDispatchThread();
+    final DebugProcessEvents debugProcess = new DebugProcessEvents(myProject);
+    debugProcess.addDebugProcessListener(new DebugProcessAdapter() {
+      public void processAttached(final DebugProcess process) {
+        process.removeDebugProcessListener(this);
+        for (Function<DebugProcess, PositionManager> factory : myCustomPositionManagerFactories) {
+          final PositionManager positionManager = factory.fun(process);
+          if (positionManager != null) {
+            process.appendPositionManager(positionManager);
+          }
+        }
+        for (PositionManagerFactory factory : Extensions.getExtensions(PositionManagerFactory.EP_NAME, myProject)) {
+          final PositionManager manager = factory.createPositionManager(debugProcess);
+          if (manager != null) {
+            process.appendPositionManager(manager);
+          }
+        }
+      }
+
+      public void processDetached(final DebugProcess process, final boolean closedByUser) {
+        debugProcess.removeDebugProcessListener(this);
+      }
+
+      public void attachException(final RunProfileState state,
+                                  final ExecutionException exception,
+                                  final RemoteConnection remoteConnection) {
+        debugProcess.removeDebugProcessListener(this);
+      }
+    });
+    final DebuggerSession session = new DebuggerSession(environment.getSessionName(), debugProcess);
+
+    final ExecutionResult executionResult = session.attach(environment);
+    if (executionResult == null) {
+      return null;
+    }
+    session.getContextManager().addListener(mySessionListener);
+    getContextManager()
+      .setState(DebuggerContextUtil.createDebuggerContext(session, session.getContextManager().getContext().getSuspendContext()),
+                session.getState(), DebuggerSession.EVENT_CONTEXT, null);
+
+    final ProcessHandler processHandler = executionResult.getProcessHandler();
+
+    synchronized (mySessions) {
+      mySessions.put(processHandler, session);
+    }
+
+    if (!(processHandler instanceof RemoteDebugProcessHandler)) {
+      // add listener only to non-remote process handler:
+      // on Unix systems destroying process does not cause VMDeathEvent to be generated,
+      // so we need to call debugProcess.stop() explicitly for graceful termination.
+      // RemoteProcessHandler on the other hand will call debugProcess.stop() as a part of destroyProcess() and detachProcess() implementation,
+      // so we shouldn't add the listener to avoid calling stop() twice
+      processHandler.addProcessListener(new ProcessAdapter() {
+        public void processWillTerminate(ProcessEvent event, boolean willBeDestroyed) {
+          final DebugProcessImpl debugProcess = getDebugProcess(event.getProcessHandler());
+          if (debugProcess != null) {
+            // if current thread is a "debugger manager thread", stop will execute synchronously
+            debugProcess.stop(willBeDestroyed);
+
+            // wait at most 10 seconds: the problem is that debugProcess.stop() can hang if there are troubles in the debuggee
+            // if processWillTerminate() is called from AWT thread debugProcess.waitFor() will block it and the whole app will hang
+            if (!DebuggerManagerThreadImpl.isManagerThread()) {
+              debugProcess.waitFor(10000);
+            }
+          }
+        }
+      });
+    }
+    myDispatcher.getMulticaster().sessionCreated(session);
+    return session;
+  }
+
+
+  public DebugProcessImpl getDebugProcess(final ProcessHandler processHandler) {
+    synchronized (mySessions) {
+      DebuggerSession session = mySessions.get(processHandler);
+      return session != null ? session.getProcess() : null;
+    }
+  }
+
+  @Nullable
+  public DebuggerSession getDebugSession(final ProcessHandler processHandler) {
+    synchronized (mySessions) {
+      return mySessions.get(processHandler);
+    }
+  }
+
+  public void addDebugProcessListener(final ProcessHandler processHandler, final DebugProcessListener listener) {
+    DebugProcessImpl debugProcess = getDebugProcess(processHandler);
+    if (debugProcess != null) {
+      debugProcess.addDebugProcessListener(listener);
+    }
+    else {
+      processHandler.addProcessListener(new ProcessAdapter() {
+        public void startNotified(ProcessEvent event) {
+          DebugProcessImpl debugProcess = getDebugProcess(processHandler);
+          if (debugProcess != null) {
+            debugProcess.addDebugProcessListener(listener);
+          }
+          processHandler.removeProcessListener(this);
+        }
+      });
+    }
+  }
+
+  public void removeDebugProcessListener(final ProcessHandler processHandler, final DebugProcessListener listener) {
+    DebugProcessImpl debugProcess = getDebugProcess(processHandler);
+    if (debugProcess != null) {
+      debugProcess.removeDebugProcessListener(listener);
+    }
+    else {
+      processHandler.addProcessListener(new ProcessAdapter() {
+        public void startNotified(ProcessEvent event) {
+          DebugProcessImpl debugProcess = getDebugProcess(processHandler);
+          if (debugProcess != null) {
+            debugProcess.removeDebugProcessListener(listener);
+          }
+          processHandler.removeProcessListener(this);
+        }
+      });
+    }
+  }
+
+  public boolean isDebuggerManagerThread() {
+    return DebuggerManagerThreadImpl.isManagerThread();
+  }
+
+  @NotNull
+  public String getComponentName() {
+    return "DebuggerManager";
+  }
+
+  public BreakpointManager getBreakpointManager() {
+    return myBreakpointManager;
+  }
+
+  public DebuggerContextImpl getContext() {
+    return getContextManager().getContext();
+  }
+
+  public DebuggerStateManager getContextManager() {
+    return myDebuggerStateManager;
+  }
+
+  public void registerPositionManagerFactory(final Function<DebugProcess, PositionManager> factory) {
+    myCustomPositionManagerFactories.add(factory);
+  }
+
+  public void unregisterPositionManagerFactory(final Function<DebugProcess, PositionManager> factory) {
+    myCustomPositionManagerFactories.remove(factory);
+  }
+
+  private static boolean hasWhitespace(String string) {
+    int length = string.length();
+    for (int i = 0; i < length; i++) {
+      if (Character.isWhitespace(string.charAt(i))) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  /* Remoting */
+  private static void checkTargetJPDAInstalled(JavaParameters parameters) throws ExecutionException {
+    final Sdk jdk = parameters.getJdk();
+    if (jdk == null) {
+      throw new ExecutionException(DebuggerBundle.message("error.jdk.not.specified"));
+    }
+    final JavaSdkVersion version = JavaSdk.getInstance().getVersion(jdk);
+    String versionString = jdk.getVersionString();
+    if (version == JavaSdkVersion.JDK_1_0 || version == JavaSdkVersion.JDK_1_1) {
+      throw new ExecutionException(DebuggerBundle.message("error.unsupported.jdk.version", versionString));
+    }
+    if (SystemInfo.isWindows && version == JavaSdkVersion.JDK_1_2) {
+      final VirtualFile homeDirectory = jdk.getHomeDirectory();
+      if (homeDirectory == null || !homeDirectory.isValid()) {
+        throw new ExecutionException(DebuggerBundle.message("error.invalid.jdk.home", versionString));
+      }
+      //noinspection HardCodedStringLiteral
+      File dllFile = new File(
+        homeDirectory.getPath().replace('/', File.separatorChar) + File.separator + "bin" + File.separator + "jdwp.dll"
+      );
+      if (!dllFile.exists()) {
+        GetJPDADialog dialog = new GetJPDADialog();
+        dialog.show();
+        throw new ExecutionException(DebuggerBundle.message("error.debug.libraries.missing"));
+      }
+    }
+  }
+
+  /**
+   * for Target JDKs versions 1.2.x - 1.3.0 the Classic VM should be used for debugging
+   */
+  private static boolean shouldForceClassicVM(Sdk jdk) {
+    if (SystemInfo.isMac) {
+      return false;
+    }
+    if (jdk == null) return false;
+
+    String version = JdkUtil.getJdkMainAttribute(jdk, Attributes.Name.IMPLEMENTATION_VERSION);
+    if (version != null) {
+      if (version.compareTo("1.4") >= 0) {
+        return false;
+      }
+      if (version.startsWith("1.2") && SystemInfo.isWindows) {
+        return true;
+      }
+      version += ".0";
+      if (version.startsWith("1.3.0") && SystemInfo.isWindows) {
+        return true;
+      }
+      if ((version.startsWith("1.3.1_07") || version.startsWith("1.3.1_08")) && SystemInfo.isWindows) {
+        return false; // fixes bug for these JDKs that it cannot start with -classic option
+      }
+    }
+
+    return DebuggerSettings.getInstance().FORCE_CLASSIC_VM;
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  public static RemoteConnection createDebugParameters(final JavaParameters parameters,
+                                                       final boolean debuggerInServerMode,
+                                                       int transport, final String debugPort,
+                                                       boolean checkValidity)
+    throws ExecutionException {
+    if (checkValidity) {
+      checkTargetJPDAInstalled(parameters);
+    }
+
+    final boolean useSockets = transport == DebuggerSettings.SOCKET_TRANSPORT;
+
+    String address = "";
+    if (debugPort == null || "".equals(debugPort)) {
+      try {
+        address = DebuggerUtils.getInstance().findAvailableDebugAddress(useSockets);
+      }
+      catch (ExecutionException e) {
+        if (checkValidity) {
+          throw e;
+        }
+      }
+    }
+    else {
+      address = debugPort;
+    }
+
+    final TransportServiceWrapper transportService = TransportServiceWrapper.getTransportService(useSockets);
+    final String debugAddress = debuggerInServerMode && useSockets ? "127.0.0.1:" + address : address;
+    String debuggeeRunProperties = "transport=" + transportService.transportId() + ",address=" + debugAddress;
+    if (debuggerInServerMode) {
+      debuggeeRunProperties += ",suspend=y,server=n";
+    }
+    else {
+      debuggeeRunProperties += ",suspend=n,server=y";
+    }
+
+    if (hasWhitespace(debuggeeRunProperties)) {
+      debuggeeRunProperties = "\"" + debuggeeRunProperties + "\"";
+    }
+    final String _debuggeeRunProperties = debuggeeRunProperties;
+
+    ApplicationManager.getApplication().runReadAction(new Runnable() {
+      @SuppressWarnings({"HardCodedStringLiteral"})
+      public void run() {
+        JavaSdkUtil.addRtJar(parameters.getClassPath());
+
+        final Sdk jdk = parameters.getJdk();
+        final boolean forceClassicVM = shouldForceClassicVM(jdk);
+        final boolean forceNoJIT = shouldForceNoJIT(jdk);
+        final String debugKey = System.getProperty(DEBUG_KEY_NAME, "-Xdebug");
+        final boolean needDebugKey = shouldAddXdebugKey(jdk) || !"-Xdebug".equals(debugKey) /*the key is non-standard*/;
+
+        if (forceClassicVM || forceNoJIT || needDebugKey || !isJVMTIAvailable(jdk)) {
+          parameters.getVMParametersList().replaceOrPrepend("-Xrunjdwp:", "-Xrunjdwp:" + _debuggeeRunProperties);
+        }
+        else {
+          // use newer JVMTI if available
+          parameters.getVMParametersList().replaceOrPrepend("-Xrunjdwp:", "");
+          parameters.getVMParametersList().replaceOrPrepend("-agentlib:jdwp=", "-agentlib:jdwp=" + _debuggeeRunProperties);
+        }
+
+        if (forceNoJIT) {
+          parameters.getVMParametersList().replaceOrPrepend("-Djava.compiler=", "-Djava.compiler=NONE");
+          parameters.getVMParametersList().replaceOrPrepend("-Xnoagent", "-Xnoagent");
+        }
+
+        if (needDebugKey) {
+          parameters.getVMParametersList().replaceOrPrepend(debugKey, debugKey);
+        }
+        else {
+          // deliberately skip outdated parameter because it can disable full-speed debugging for some jdk builds
+          // see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6272174
+          parameters.getVMParametersList().replaceOrPrepend("-Xdebug", "");
+        }
+
+        parameters.getVMParametersList().replaceOrPrepend("-classic", forceClassicVM ? "-classic" : "");
+      }
+    });
+
+    return new RemoteConnection(useSockets, "127.0.0.1", address, debuggerInServerMode);
+  }
+
+  private static boolean shouldForceNoJIT(Sdk jdk) {
+    if (DebuggerSettings.getInstance().DISABLE_JIT) {
+      return true;
+    }
+    if (jdk != null) {
+      final String version = JdkUtil.getJdkMainAttribute(jdk, Attributes.Name.IMPLEMENTATION_VERSION);
+      if (version != null && (version.startsWith("1.2") || version.startsWith("1.3"))) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  private static boolean shouldAddXdebugKey(Sdk jdk) {
+    if (jdk == null) {
+      return true; // conservative choice
+    }
+    if (DebuggerSettings.getInstance().DISABLE_JIT) {
+      return true;
+    }
+
+    //if (ApplicationManager.getApplication().isUnitTestMode()) {
+    // need this in unit tests to avoid false alarms when comparing actual output with expected output
+    //return true;
+    //}
+
+    final String version = JdkUtil.getJdkMainAttribute(jdk, Attributes.Name.IMPLEMENTATION_VERSION);
+    return version == null ||
+           //version.startsWith("1.5") ||
+           version.startsWith("1.4") ||
+           version.startsWith("1.3") ||
+           version.startsWith("1.2") ||
+           version.startsWith("1.1") ||
+           version.startsWith("1.0");
+  }
+
+  private static boolean isJVMTIAvailable(Sdk jdk) {
+    if (jdk == null) {
+      return false; // conservative choice
+    }
+
+    final String version = JdkUtil.getJdkMainAttribute(jdk, Attributes.Name.IMPLEMENTATION_VERSION);
+    if (version == null) {
+      return false;
+    }
+    return !(version.startsWith("1.4") ||
+             version.startsWith("1.3") ||
+             version.startsWith("1.2") ||
+             version.startsWith("1.1") ||
+             version.startsWith("1.0"));
+  }
+
+  public static RemoteConnection createDebugParameters(final JavaParameters parameters,
+                                                       GenericDebuggerRunnerSettings settings,
+                                                       boolean checkValidity)
+    throws ExecutionException {
+    return createDebugParameters(parameters, settings.LOCAL, settings.getTransport(), settings.DEBUG_PORT, checkValidity);
+  }
+
+  private static class MyDebuggerStateManager extends DebuggerStateManager {
+    private DebuggerSession myDebuggerSession;
+
+    public DebuggerContextImpl getContext() {
+      return myDebuggerSession == null ? DebuggerContextImpl.EMPTY_CONTEXT : myDebuggerSession.getContextManager().getContext();
+    }
+
+    public void setState(final DebuggerContextImpl context, int state, int event, String description) {
+      ApplicationManager.getApplication().assertIsDispatchThread();
+      myDebuggerSession = context.getDebuggerSession();
+      if (myDebuggerSession != null) {
+        myDebuggerSession.getContextManager().setState(context, state, event, description);
+      }
+      else {
+        fireStateChanged(context, event);
+      }
+    }
+  }
+
+  private void dispose(DebuggerSession session) {
+    ProcessHandler processHandler = session.getProcess().getExecutionResult().getProcessHandler();
+
+    synchronized (mySessions) {
+      DebuggerSession removed = mySessions.remove(processHandler);
+      LOG.assertTrue(removed != null);
+      myDispatcher.getMulticaster().sessionRemoved(session);
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerManagerListener.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerManagerListener.java
new file mode 100644
index 0000000..ff4261f
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerManagerListener.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl;
+
+import java.util.EventListener;
+
+public interface DebuggerManagerListener extends EventListener{
+  void sessionCreated(DebuggerSession session);
+  void sessionAttached(DebuggerSession session);
+  void sessionDetached(DebuggerSession session);
+  void sessionRemoved(DebuggerSession session);
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerSession.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerSession.java
new file mode 100644
index 0000000..e3773a3
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerSession.java
@@ -0,0 +1,628 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl;
+
+import com.intellij.debugger.*;
+import com.intellij.debugger.actions.DebuggerActions;
+import com.intellij.debugger.engine.*;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationListener;
+import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
+import com.intellij.debugger.engine.requests.RequestManagerImpl;
+import com.intellij.debugger.jdi.StackFrameProxyImpl;
+import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
+import com.intellij.debugger.ui.breakpoints.Breakpoint;
+import com.intellij.debugger.ui.breakpoints.BreakpointWithHighlighter;
+import com.intellij.debugger.ui.breakpoints.LineBreakpoint;
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.ExecutionResult;
+import com.intellij.execution.Executor;
+import com.intellij.execution.configurations.ModuleRunProfile;
+import com.intellij.execution.configurations.RemoteConnection;
+import com.intellij.execution.configurations.RemoteState;
+import com.intellij.execution.configurations.RunProfileState;
+import com.intellij.execution.process.ProcessOutputTypes;
+import com.intellij.execution.runners.ProgramRunner;
+import com.intellij.idea.ActionsBundle;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.ModalityState;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.Messages;
+import com.intellij.openapi.util.Computable;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.util.Pair;
+import com.intellij.psi.PsiCompiledElement;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.unscramble.ThreadState;
+import com.intellij.util.Alarm;
+import com.intellij.xdebugger.AbstractDebuggerSession;
+import com.intellij.xdebugger.impl.evaluate.quick.common.ValueLookupManager;
+import com.sun.jdi.ObjectCollectedException;
+import com.sun.jdi.ThreadReference;
+import com.sun.jdi.event.Event;
+import com.sun.jdi.request.EventRequest;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class DebuggerSession implements AbstractDebuggerSession {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.impl.DebuggerSession");
+  // flags
+  private final MyDebuggerStateManager myContextManager;
+
+  public static final int STATE_STOPPED = 0;
+  public static final int STATE_RUNNING = 1;
+  public static final int STATE_WAITING_ATTACH = 2;
+  public static final int STATE_PAUSED = 3;
+  public static final int STATE_WAIT_EVALUATION = 5;
+  public static final int STATE_DISPOSED = 6;
+
+  public static final int EVENT_ATTACHED = 0;
+  public static final int EVENT_DETACHED = 1;
+  public static final int EVENT_RESUME = 4;
+  public static final int EVENT_STEP = 5;
+  public static final int EVENT_PAUSE = 6;
+  public static final int EVENT_REFRESH = 7;
+  public static final int EVENT_CONTEXT = 8;
+  public static final int EVENT_START_WAIT_ATTACH = 9;
+  public static final int EVENT_DISPOSE = 10;
+  public static final int EVENT_REFRESH_VIEWS_ONLY = 11;
+  public static final int EVENT_THREADS_REFRESH = 12;
+
+  private volatile boolean myIsEvaluating;
+  private volatile int myIgnoreFiltersFrameCountThreshold = 0;
+
+  private DebuggerSessionState myState = null;
+
+  private final String mySessionName;
+  private final DebugProcessImpl myDebugProcess;
+  private @NotNull GlobalSearchScope mySearchScope;
+
+  private final DebuggerContextImpl SESSION_EMPTY_CONTEXT;
+  //Thread, user is currently stepping through
+  private final Set<ThreadReferenceProxyImpl> mySteppingThroughThreads = new HashSet<ThreadReferenceProxyImpl>();
+  protected final Alarm myUpdateAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD);
+
+  private boolean myModifiedClassesScanRequired = false;
+
+  public boolean isSteppingThrough(ThreadReferenceProxyImpl threadProxy) {
+    return mySteppingThroughThreads.contains(threadProxy);
+  }
+
+  @NotNull
+  public GlobalSearchScope getSearchScope() {
+    LOG.assertTrue(mySearchScope != null, "Accessing Session's search scope before its initialization");
+    return mySearchScope;
+  }
+
+  public boolean isModifiedClassesScanRequired() {
+    return myModifiedClassesScanRequired;
+  }
+
+  public void setModifiedClassesScanRequired(boolean modifiedClassesScanRequired) {
+    myModifiedClassesScanRequired = modifiedClassesScanRequired;
+  }
+
+  private class MyDebuggerStateManager extends DebuggerStateManager {
+    private DebuggerContextImpl myDebuggerContext;
+
+    MyDebuggerStateManager() {
+      myDebuggerContext = SESSION_EMPTY_CONTEXT;
+    }
+
+    public DebuggerContextImpl getContext() {
+      return myDebuggerContext;
+    }
+
+    /**
+     * actually state changes not in the same sequence as you call setState
+     * the 'resuming' setState with context.getSuspendContext() == null may be set prior to
+     * the setState for the context with context.getSuspendContext()
+     *
+     * in this case we assume that the latter setState is ignored
+     * since the thread was resumed
+     */
+    public void setState(final DebuggerContextImpl context, final int state, final int event, final String description) {
+      ApplicationManager.getApplication().assertIsDispatchThread();
+      LOG.assertTrue(context.getDebuggerSession() == DebuggerSession.this || context.getDebuggerSession() == null);
+      final Runnable setStateRunnable = new Runnable() {
+        public void run() {
+          LOG.assertTrue(myDebuggerContext.isInitialised());
+          myDebuggerContext = context;
+          if (LOG.isDebugEnabled()) {
+            LOG.debug("DebuggerSession state = " + state + ", event = " + event);
+          }
+
+          myIsEvaluating = false;
+
+          myState = new DebuggerSessionState(state, description);
+          fireStateChanged(context, event);
+        }
+      };
+
+      if(context.getSuspendContext() == null) {
+        setStateRunnable.run();
+      }
+      else {
+        getProcess().getManagerThread().schedule(new SuspendContextCommandImpl(context.getSuspendContext()) {
+          public void contextAction() throws Exception {
+            context.initCaches();
+            DebuggerInvocationUtil.swingInvokeLater(getProject(), setStateRunnable);
+          }
+        });
+      }
+    }
+  }
+
+  protected DebuggerSession(String sessionName, final DebugProcessImpl debugProcess) {
+    mySessionName  = sessionName;
+    myDebugProcess = debugProcess;
+    SESSION_EMPTY_CONTEXT = DebuggerContextImpl.createDebuggerContext(this, null, null, null);
+    myContextManager = new MyDebuggerStateManager();
+    myState = new DebuggerSessionState(STATE_STOPPED, null);
+    myDebugProcess.addDebugProcessListener(new MyDebugProcessListener(debugProcess));
+    myDebugProcess.addEvaluationListener(new MyEvaluationListener());
+    ValueLookupManager.getInstance(getProject()).startListening();
+  }
+
+  public DebuggerStateManager getContextManager() {
+    return myContextManager;
+  }
+
+  public Project getProject() {
+    return getProcess().getProject();
+  }
+
+  public String getSessionName() {
+    return mySessionName;
+  }
+
+  public DebugProcessImpl getProcess() {
+    return myDebugProcess;
+  }
+
+  private static class DebuggerSessionState {
+    final int myState;
+    final String myDescription;
+
+    public DebuggerSessionState(int state, String description) {
+      myState = state;
+      myDescription = description;
+    }
+  }
+
+  public int getState() {
+    return myState.myState;
+  }
+
+  public String getStateDescription() {
+    if (myState.myDescription != null) {
+      return myState.myDescription;
+    }
+
+    switch (myState.myState) {
+      case STATE_STOPPED:
+        return DebuggerBundle.message("status.debug.stopped");
+      case STATE_RUNNING:
+        return DebuggerBundle.message("status.app.running");
+      case STATE_WAITING_ATTACH:
+        RemoteConnection connection = getProcess().getConnection();
+        final String addressDisplayName = DebuggerBundle.getAddressDisplayName(connection);
+        final String transportName = DebuggerBundle.getTransportName(connection);
+        return connection.isServerMode() ? DebuggerBundle.message("status.listening", addressDisplayName, transportName) : DebuggerBundle.message("status.connecting", addressDisplayName, transportName);
+      case STATE_PAUSED:
+        return DebuggerBundle.message("status.paused");
+      case STATE_WAIT_EVALUATION:
+        return DebuggerBundle.message("status.waiting.evaluation.result");
+      case STATE_DISPOSED:
+        return DebuggerBundle.message("status.debug.stopped");
+    }
+    return myState.myDescription;
+  }
+
+  /* Stepping */
+  private void resumeAction(final DebugProcessImpl.ResumeCommand command, int event) {
+    getContextManager().setState(SESSION_EMPTY_CONTEXT, STATE_WAIT_EVALUATION, event, null);
+    myDebugProcess.getManagerThread().schedule(command);
+  }
+
+  public void stepOut() {
+    final SuspendContextImpl suspendContext = getSuspendContext();
+    final DebugProcessImpl.ResumeCommand cmd = myDebugProcess.createStepOutCommand(suspendContext);
+    mySteppingThroughThreads.add(cmd.getContextThread());
+    resumeAction(cmd, EVENT_STEP);
+  }
+
+  public void stepOver(boolean ignoreBreakpoints) {
+    final SuspendContextImpl suspendContext = getSuspendContext();
+    final DebugProcessImpl.ResumeCommand cmd = myDebugProcess.createStepOverCommand(suspendContext, ignoreBreakpoints);
+    mySteppingThroughThreads.add(cmd.getContextThread());
+    resumeAction(cmd, EVENT_STEP);
+  }
+
+  public void stepInto(final boolean ignoreFilters, final @Nullable RequestHint.SmartStepFilter smartStepFilter) {
+    final SuspendContextImpl suspendContext = getSuspendContext();
+    final DebugProcessImpl.ResumeCommand cmd = myDebugProcess.createStepIntoCommand(suspendContext, ignoreFilters, smartStepFilter);
+    mySteppingThroughThreads.add(cmd.getContextThread());
+    resumeAction(cmd, EVENT_STEP);
+  }
+
+  public void runToCursor(Document document, int line, final boolean ignoreBreakpoints) {
+    try {
+      DebugProcessImpl.ResumeCommand runToCursorCommand = myDebugProcess.createRunToCursorCommand(getSuspendContext(), document, line, ignoreBreakpoints);
+      mySteppingThroughThreads.add(runToCursorCommand.getContextThread());
+      resumeAction(runToCursorCommand, EVENT_STEP);
+    }
+    catch (EvaluateException e) {
+      Messages.showErrorDialog(e.getMessage(), ActionsBundle.actionText(DebuggerActions.RUN_TO_CURSOR));
+    }
+  }
+
+
+  public void resume() {
+    final SuspendContextImpl suspendContext = getSuspendContext();
+    if(suspendContext != null) {
+      mySteppingThroughThreads.clear();
+      resetIgnoreStepFiltersFlag();
+      resumeAction(myDebugProcess.createResumeCommand(suspendContext), EVENT_RESUME);
+    }
+  }
+
+  private void resetIgnoreStepFiltersFlag() {
+    myIgnoreFiltersFrameCountThreshold = 0;
+  }
+
+  public void setIgnoreStepFiltersFlag(int currentStackFrameCount) {
+    myIgnoreFiltersFrameCountThreshold = currentStackFrameCount;
+  }
+
+  public boolean shouldIgnoreSteppingFilters() {
+    return myIgnoreFiltersFrameCountThreshold > 0;
+  }
+
+  public void pause() {
+    myDebugProcess.getManagerThread().schedule(myDebugProcess.createPauseCommand());
+  }
+
+  /*Presentation*/
+
+  public void showExecutionPoint() {
+    getContextManager().setState(DebuggerContextUtil.createDebuggerContext(this, getSuspendContext()), STATE_PAUSED, EVENT_REFRESH, null);
+  }
+
+  public void refresh(final boolean refreshViewsOnly) {
+    final int state = getState();
+    DebuggerContextImpl context = myContextManager.getContext();
+    DebuggerContextImpl newContext = DebuggerContextImpl.createDebuggerContext(this, context.getSuspendContext(), context.getThreadProxy(), context.getFrameProxy());
+    myContextManager.setState(newContext, state, refreshViewsOnly? EVENT_REFRESH_VIEWS_ONLY : EVENT_REFRESH, null);
+  }
+
+  public void dispose() {
+    ApplicationManager.getApplication().assertIsDispatchThread();
+    getProcess().dispose();
+    getContextManager().setState(SESSION_EMPTY_CONTEXT, STATE_DISPOSED, EVENT_DISPOSE, null);
+    Disposer.dispose(myUpdateAlarm);
+  }
+
+  // ManagerCommands
+  public boolean isStopped() {
+    return getState() == STATE_STOPPED;
+  }
+
+  public boolean isAttached() {
+    return !isStopped() && getState() != STATE_WAITING_ATTACH;
+  }
+
+  public boolean isPaused() {
+    return getState() == STATE_PAUSED;
+  }
+
+  public boolean isConnecting() {
+    return getState() == STATE_WAITING_ATTACH;
+  }
+
+  public boolean isEvaluating() {
+    return myIsEvaluating;
+  }
+
+  public boolean isRunning() {
+    return getState() == STATE_RUNNING && !getProcess().getExecutionResult().getProcessHandler().isProcessTerminated();
+  }
+
+  private SuspendContextImpl getSuspendContext() {
+    ApplicationManager.getApplication().assertIsDispatchThread();
+    return getContextManager().getContext().getSuspendContext();
+  }
+
+  @Nullable
+  protected ExecutionResult attach(@NotNull final Executor executor,
+                                   @NotNull final ProgramRunner runner,
+                                   final ModuleRunProfile profile,
+                                   final RunProfileState state,
+                                   final RemoteConnection remoteConnection,
+                                   final boolean pollConnection) throws ExecutionException {
+    return attach(new DefaultDebugEnvironment(myDebugProcess.getProject(),
+                                              executor,
+                                              runner,
+                                              profile,
+                                              state,
+                                              remoteConnection,
+                                              pollConnection));
+  }
+
+  @Nullable
+  protected ExecutionResult attach(DebugEnvironment environment) throws ExecutionException {
+    RemoteConnection remoteConnection = environment.getRemoteConnection();
+    final String addressDisplayName = DebuggerBundle.getAddressDisplayName(remoteConnection);
+    final String transportName = DebuggerBundle.getTransportName(remoteConnection);
+    mySearchScope = environment.getSearchScope();
+    final ExecutionResult executionResult = myDebugProcess.attachVirtualMachine(environment, this);
+    getContextManager().setState(SESSION_EMPTY_CONTEXT, STATE_WAITING_ATTACH, EVENT_START_WAIT_ATTACH, DebuggerBundle.message("status.waiting.attach", addressDisplayName, transportName));
+    return executionResult;
+  }
+
+  private class MyDebugProcessListener extends DebugProcessAdapterImpl {
+    private final DebugProcessImpl myDebugProcess;
+
+    public MyDebugProcessListener(final DebugProcessImpl debugProcess) {
+      myDebugProcess = debugProcess;
+    }
+
+    //executed in manager thread
+    public void connectorIsReady() {
+      DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
+        public void run() {
+          RemoteConnection connection = myDebugProcess.getConnection();
+          final String addressDisplayName = DebuggerBundle.getAddressDisplayName(connection);
+          final String transportName = DebuggerBundle.getTransportName(connection);
+          final String connectionStatusMessage = connection.isServerMode() ? DebuggerBundle.message("status.listening", addressDisplayName, transportName) : DebuggerBundle.message("status.connecting", addressDisplayName, transportName);
+          getContextManager().setState(SESSION_EMPTY_CONTEXT, DebuggerSession.STATE_WAITING_ATTACH, DebuggerSession.EVENT_START_WAIT_ATTACH, connectionStatusMessage);
+        }
+      });
+    }
+
+    public void paused(final SuspendContextImpl suspendContext) {
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("paused");
+      }
+
+      ThreadReferenceProxyImpl currentThread   = suspendContext.getThread();
+      final StackFrameContext positionContext;
+
+      if (currentThread == null) {
+        //Pause pressed
+        LOG.assertTrue(suspendContext.getSuspendPolicy() == EventRequest.SUSPEND_ALL);
+        SuspendContextImpl oldContext = getProcess().getSuspendManager().getPausedContext();
+
+        if (oldContext != null) {
+          currentThread = oldContext.getThread();
+        }
+
+        if(currentThread == null) {
+          final Collection<ThreadReferenceProxyImpl> allThreads = getProcess().getVirtualMachineProxy().allThreads();
+          // heuristics: try to pre-select EventDispatchThread
+          for (final ThreadReferenceProxyImpl thread : allThreads) {
+            if (ThreadState.isEDT(thread.name())) {
+              currentThread = thread;
+              break;
+            }
+          }
+          if (currentThread == null) {
+            // heuristics: display the first thread with RUNNABLE status
+            for (final ThreadReferenceProxyImpl thread : allThreads) {
+              currentThread = thread;
+              if (currentThread.status() == ThreadReference.THREAD_STATUS_RUNNING) {
+                break;
+              }
+            }
+          }
+        }
+
+        StackFrameProxyImpl proxy = null;
+        if (currentThread != null) {
+          try {
+            while (!currentThread.isSuspended()) {
+              // wait until thread is considered suspended. Querying data from a thread immediately after VM.suspend()
+              // may result in IncompatibleThreadStateException, most likely some time after suspend() VM erroneously thinks that thread is still running
+              try {
+                Thread.sleep(10);
+              }
+              catch (InterruptedException ignored) {}
+            }
+            proxy = (currentThread.frameCount() > 0) ? currentThread.frame(0) : null;
+          }
+          catch (ObjectCollectedException e) {
+            proxy = null;
+          }
+          catch (EvaluateException e) {
+            proxy = null;
+            LOG.error(e);
+          }
+        }
+        positionContext = new SimpleStackFrameContext(proxy, myDebugProcess);
+      }
+      else {
+        positionContext = suspendContext;
+      }
+
+      if (currentThread != null) {
+        try {
+          final int frameCount = currentThread.frameCount();
+          if (frameCount == 0 || (frameCount < myIgnoreFiltersFrameCountThreshold)) {
+            resetIgnoreStepFiltersFlag();
+          }
+        }
+        catch (EvaluateException e) {
+          LOG.info(e);
+          resetIgnoreStepFiltersFlag();
+        }
+      }
+
+      SourcePosition position = PsiDocumentManager.getInstance(getProject()).commitAndRunReadAction(new Computable<SourcePosition>() {
+        public @Nullable SourcePosition compute() {
+          return ContextUtil.getSourcePosition(positionContext);
+        }
+      });
+
+      if (position != null) {
+        final List<Pair<Breakpoint, Event>> eventDescriptors = DebuggerUtilsEx.getEventDescriptors(suspendContext);
+        final RequestManagerImpl requestsManager = suspendContext.getDebugProcess().getRequestsManager();
+        final PsiFile foundFile = position.getFile();
+        final boolean sourceMissing = foundFile == null || foundFile instanceof PsiCompiledElement;
+        for (Pair<Breakpoint, Event> eventDescriptor : eventDescriptors) {
+          Breakpoint breakpoint = eventDescriptor.getFirst();
+          if (breakpoint instanceof LineBreakpoint) {
+            final SourcePosition breakpointPosition = ((BreakpointWithHighlighter)breakpoint).getSourcePosition();
+            if (breakpointPosition == null || (!sourceMissing && breakpointPosition.getLine() != position.getLine())) {
+              requestsManager.deleteRequest(breakpoint);
+              requestsManager.setInvalid(breakpoint, DebuggerBundle.message("error.invalid.breakpoint.source.changed"));
+              breakpoint.updateUI();
+            }
+            else if (sourceMissing) {
+              // adjust position to be position of the breakpoint in order to show the real originator of the event
+              position = breakpointPosition;
+              String className;
+              try {
+                className = positionContext.getFrameProxy().location().declaringType().name();
+              }
+              catch (EvaluateException e) {
+                className = "";
+              }
+              requestsManager.setInvalid(breakpoint, DebuggerBundle.message("error.invalid.breakpoint.source.not.found", className));
+              breakpoint.updateUI();
+            }
+          }
+        }
+      }
+
+      final DebuggerContextImpl debuggerContext = DebuggerContextImpl.createDebuggerContext(DebuggerSession.this, suspendContext, currentThread, null);
+      debuggerContext.setPositionCache(position);
+
+      DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
+        public void run() {
+          getContextManager().setState(debuggerContext, STATE_PAUSED, EVENT_PAUSE, null);
+        }
+      });
+    }
+
+    public void resumed(final SuspendContextImpl suspendContext) {
+      final SuspendContextImpl currentContext = getProcess().getSuspendManager().getPausedContext();
+      DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
+        public void run() {
+          if (currentContext != null) {
+            getContextManager().setState(DebuggerContextUtil.createDebuggerContext(DebuggerSession.this, currentContext), STATE_PAUSED, EVENT_CONTEXT, null);
+          }
+          else {
+            getContextManager().setState(SESSION_EMPTY_CONTEXT, STATE_RUNNING, EVENT_CONTEXT, null);
+          }
+        }
+      });
+    }
+
+    public void processAttached(final DebugProcessImpl process) {
+      final RemoteConnection connection = getProcess().getConnection();
+      final String addressDisplayName = DebuggerBundle.getAddressDisplayName(connection);
+      final String transportName = DebuggerBundle.getTransportName(connection);
+      final String message = DebuggerBundle.message("status.connected", addressDisplayName, transportName);
+
+      process.getExecutionResult().getProcessHandler().notifyTextAvailable(message + "\n", ProcessOutputTypes.SYSTEM);
+      DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
+        public void run() {
+          getContextManager().setState(SESSION_EMPTY_CONTEXT, STATE_RUNNING, EVENT_ATTACHED, message);
+        }
+      });
+    }
+
+    public void attachException(final RunProfileState state, final ExecutionException exception, final RemoteConnection remoteConnection) {
+      DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
+        public void run() {
+          String message = "";
+          if (state instanceof RemoteState) {
+            message = DebuggerBundle.message("status.connect.failed", DebuggerBundle.getAddressDisplayName(remoteConnection), DebuggerBundle.getTransportName(remoteConnection));
+          }
+          message += exception.getMessage();
+          getContextManager().setState(SESSION_EMPTY_CONTEXT, STATE_STOPPED, EVENT_DETACHED, message);
+        }
+      });
+    }
+
+    public void processDetached(final DebugProcessImpl debugProcess, boolean closedByUser) {
+      if (!closedByUser) {
+        ExecutionResult executionResult = debugProcess.getExecutionResult();
+        if(executionResult != null) {
+          final RemoteConnection connection = getProcess().getConnection();
+          final String addressDisplayName = DebuggerBundle.getAddressDisplayName(connection);
+          final String transportName = DebuggerBundle.getTransportName(connection);
+          executionResult.getProcessHandler().notifyTextAvailable(DebuggerBundle.message("status.disconnected", addressDisplayName, transportName) + "\n", ProcessOutputTypes.SYSTEM);
+        }
+      }
+      DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
+        public void run() {
+          final RemoteConnection connection = getProcess().getConnection();
+          final String addressDisplayName = DebuggerBundle.getAddressDisplayName(connection);
+          final String transportName = DebuggerBundle.getTransportName(connection);
+          getContextManager().setState(SESSION_EMPTY_CONTEXT, STATE_STOPPED, EVENT_DETACHED, DebuggerBundle.message("status.disconnected", addressDisplayName, transportName));
+        }
+      });
+      mySteppingThroughThreads.clear();
+    }
+
+    public void threadStarted(DebugProcess proc, ThreadReference thread) {
+      notifyThreadsRefresh();
+    }
+
+    public void threadStopped(DebugProcess proc, ThreadReference thread) {
+      notifyThreadsRefresh();
+    }
+    
+    private void notifyThreadsRefresh() {
+      if (!myUpdateAlarm.isDisposed()) {
+        myUpdateAlarm.cancelAllRequests();
+        myUpdateAlarm.addRequest(new Runnable() {
+          public void run() {
+            final DebuggerStateManager contextManager = getContextManager();
+            contextManager.fireStateChanged(contextManager.getContext(), EVENT_THREADS_REFRESH);
+          }
+        }, 100, ModalityState.NON_MODAL);
+      }
+    }
+  }
+
+  private class MyEvaluationListener implements EvaluationListener {
+    public void evaluationStarted(SuspendContextImpl context) {
+      myIsEvaluating = true;
+    }
+
+    public void evaluationFinished(final SuspendContextImpl context) {
+      myIsEvaluating = false;
+      DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
+        public void run() {
+          if (context != getSuspendContext()) {
+            getContextManager().setState(DebuggerContextUtil.createDebuggerContext(DebuggerSession.this, context), STATE_PAUSED, EVENT_REFRESH, null);
+          }
+        }
+      });
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerStateManager.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerStateManager.java
new file mode 100644
index 0000000..e07ab9b
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerStateManager.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl;
+
+import com.intellij.util.EventDispatcher;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: lex
+ * Date: Jun 4, 2003
+ * Time: 12:45:56 PM
+ * To change this template use Options | File Templates.
+ */
+public abstract class DebuggerStateManager {
+  private final EventDispatcher<DebuggerContextListener> myEventDispatcher = EventDispatcher.create(DebuggerContextListener.class);
+
+  public abstract DebuggerContextImpl getContext();
+
+  public abstract void setState(DebuggerContextImpl context, int state, int event, String description);
+
+  //we allow add listeners inside DebuggerContextListener.changeEvent
+  public void addListener(DebuggerContextListener listener){
+    myEventDispatcher.addListener(listener);
+  }
+
+  //we allow remove listeners inside DebuggerContextListener.changeEvent
+  public void removeListener(DebuggerContextListener listener){
+    myEventDispatcher.removeListener(listener);
+  }
+
+  protected void fireStateChanged(DebuggerContextImpl newContext, int event) {
+    myEventDispatcher.getMulticaster().changeEvent(newContext, event);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerTask.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerTask.java
new file mode 100644
index 0000000..81639f2
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerTask.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl;
+
+/**
+ * @author lex
+ */
+public interface DebuggerTask extends PrioritizedTask {
+  void release();
+
+  void hold();
+
+  void waitFor();
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerTaskImpl.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerTaskImpl.java
new file mode 100644
index 0000000..6e75e66
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerTaskImpl.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl;
+
+/**
+ * @author lex
+ */
+public abstract class DebuggerTaskImpl implements DebuggerTask {
+  private int myHolds = 0;
+  
+  public synchronized final void release() {
+    if (myHolds > 0) {
+      if (--myHolds == 0) {
+        notifyAll();
+      }
+    }
+  }
+
+  public synchronized final void hold() {
+    myHolds++;
+  }
+
+  public synchronized final void waitFor() {
+    while (myHolds > 0) {
+      try {
+        wait();
+      }
+      catch (InterruptedException ignored) {
+      }
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsEx.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsEx.java
new file mode 100644
index 0000000..88c3f50
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsEx.java
@@ -0,0 +1,591 @@
+/*
+ * Copyright 2000-2011 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.
+ */
+
+/*
+ * Class DebuggerUtilsEx
+ * @author Jeka
+ */
+package com.intellij.debugger.impl;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
+import com.intellij.debugger.engine.DebuggerUtils;
+import com.intellij.debugger.engine.SuspendContextImpl;
+import com.intellij.debugger.engine.evaluation.*;
+import com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilder;
+import com.intellij.debugger.engine.requests.RequestManagerImpl;
+import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
+import com.intellij.debugger.requests.Requestor;
+import com.intellij.debugger.ui.CompletionEditor;
+import com.intellij.debugger.ui.breakpoints.Breakpoint;
+import com.intellij.debugger.ui.tree.DebuggerTreeNode;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.*;
+import com.intellij.psi.*;
+import com.intellij.ui.classFilter.ClassFilter;
+import com.sun.jdi.*;
+import com.sun.jdi.event.Event;
+import org.jdom.Attribute;
+import org.jdom.Element;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.*;
+import java.util.regex.PatternSyntaxException;
+
+public abstract class DebuggerUtilsEx extends DebuggerUtils {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.impl.DebuggerUtilsEx");
+
+  private static final int MAX_LABEL_SIZE = 255;
+
+  /**
+   * @param context
+   * @return all CodeFragmentFactoryProviders that provide code fragment factories sutable in the context given
+   */
+  public static List<CodeFragmentFactory> getCodeFragmentFactories(@Nullable PsiElement context) {
+    final DefaultCodeFragmentFactory defaultFactry = DefaultCodeFragmentFactory.getInstance();
+    final CodeFragmentFactory[] providers = ApplicationManager.getApplication().getExtensions(CodeFragmentFactory.EXTENSION_POINT_NAME);
+    final List<CodeFragmentFactory> suitableFactories = new ArrayList<CodeFragmentFactory>(providers.length);
+    if (providers.length > 0) {
+      for (CodeFragmentFactory factory : providers) {
+        if (factory != defaultFactry && factory.isContextAccepted(context)) {
+          suitableFactories.add(factory);
+        }
+      }
+    }
+    suitableFactories.add(defaultFactry); // let default factory be the last one
+    return suitableFactories;
+  }
+
+
+  public static PsiMethod findPsiMethod(PsiFile file, int offset) {
+    PsiElement element = null;
+
+    while(offset >= 0) {
+      element = file.findElementAt(offset);
+      if(element != null) break;
+      offset --;
+    }
+
+    for (; element != null; element = element.getParent()) {
+      if (element instanceof PsiClass) return null;
+      if (element instanceof PsiMethod) return (PsiMethod)element;
+    }
+    return null;
+  }
+
+
+  public static boolean isAssignableFrom(final String baseQualifiedName, ReferenceType checkedType) {
+    if (CommonClassNames.JAVA_LANG_OBJECT.equals(baseQualifiedName)) {
+      return true;
+    }
+    return getSuperClass(baseQualifiedName, checkedType) != null;
+  }
+
+  public static ReferenceType getSuperClass(final String baseQualifiedName, ReferenceType checkedType) {
+    if (baseQualifiedName.equals(checkedType.name())) {
+      return checkedType;
+    }
+
+    if (checkedType instanceof ClassType) {
+      ClassType classType = (ClassType)checkedType;
+      ClassType superClassType = classType.superclass();
+      if (superClassType != null) {
+        ReferenceType superClass = getSuperClass(baseQualifiedName, superClassType);
+        if (superClass != null) {
+          return superClass;
+        }
+      }
+      List<InterfaceType> ifaces = classType.allInterfaces();
+      for (Iterator<InterfaceType> it = ifaces.iterator(); it.hasNext();) {
+        InterfaceType iface = it.next();
+        ReferenceType superClass = getSuperClass(baseQualifiedName, iface);
+        if (superClass != null) {
+          return superClass;
+        }
+      }
+    }
+
+    if (checkedType instanceof InterfaceType) {
+      List<InterfaceType> list = ((InterfaceType)checkedType).superinterfaces();
+      for (Iterator<InterfaceType> it = list.iterator(); it.hasNext();) {
+        InterfaceType superInterface = it.next();
+        ReferenceType superClass = getSuperClass(baseQualifiedName, superInterface);
+        if (superClass != null) {
+          return superClass;
+        }
+      }
+    }
+    return null;
+  }
+
+  public static boolean valuesEqual(Value val1, Value val2) {
+    if (val1 == null) {
+      return val2 == null;
+    }
+    if (val2 == null) {
+      return false;
+    }
+    if (val1 instanceof StringReference && val2 instanceof StringReference) {
+      return ((StringReference)val1).value().equals(((StringReference)val2).value());
+    }
+    return val1.equals(val2);
+  }
+
+  public static String getValueOrErrorAsString(final EvaluationContext evaluationContext, Value value) {
+    try {
+      return getValueAsString(evaluationContext, value);
+    }
+    catch (EvaluateException e) {
+      return e.getMessage();
+    }
+  }
+
+  public static boolean isCharOrInteger(Value value) {
+    return value instanceof CharValue || isInteger(value);
+  }
+
+  private static Set<String> myCharOrIntegers;
+
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  public static boolean isCharOrIntegerArray(Value value) {
+    if (value == null) return false;
+    if (myCharOrIntegers == null) {
+      myCharOrIntegers = new HashSet<String>();
+      myCharOrIntegers.add("C");
+      myCharOrIntegers.add("B");
+      myCharOrIntegers.add("S");
+      myCharOrIntegers.add("I");
+      myCharOrIntegers.add("J");
+    }
+
+    String signature = value.type().signature();
+    int i;
+    for (i = 0; signature.charAt(i) == '['; i++) ;
+    if (i == 0) return false;
+    signature = signature.substring(i, signature.length());
+    return myCharOrIntegers.contains(signature);
+  }
+
+  public static ClassFilter create(Element element) throws InvalidDataException {
+    ClassFilter filter = new ClassFilter();
+    filter.readExternal(element);
+    return filter;
+  }
+
+  private static boolean isFiltered(ClassFilter classFilter, String qName) {
+    if (!classFilter.isEnabled()) {
+      return false;
+    }
+    try {
+      if (classFilter.matches(qName)) {
+        return true;
+      }
+    }
+    catch (PatternSyntaxException e) {
+      LOG.debug(e);
+    }
+    return false;
+  }
+
+  public static boolean isFiltered(String qName, ClassFilter[] classFilters) {
+    return isFiltered(qName, Arrays.asList(classFilters));
+  }
+  
+  public static boolean isFiltered(String qName, List<ClassFilter> classFilters) {
+    if(qName.indexOf('[') != -1) {
+      return false; //is array
+    }
+
+    for (ClassFilter filter : classFilters) {
+      if (isFiltered(filter, qName)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  public static ClassFilter[] readFilters(List children) throws InvalidDataException {
+    if (children == null || children.size() == 0) {
+      return ClassFilter.EMPTY_ARRAY;
+    }
+    List<ClassFilter> classFiltersList = new ArrayList<ClassFilter>(children.size());
+    for (Iterator i = children.iterator(); i.hasNext();) {
+      final ClassFilter classFilter = new ClassFilter();
+      classFilter.readExternal((Element)i.next());
+      classFiltersList.add(classFilter);
+    }
+    return classFiltersList.toArray(new ClassFilter[classFiltersList.size()]);
+  }
+
+  public static void writeFilters(Element parentNode, @NonNls String tagName, ClassFilter[] filters) throws WriteExternalException {
+    for (ClassFilter filter : filters) {
+      Element element = new Element(tagName);
+      parentNode.addContent(element);
+      filter.writeExternal(element);
+    }
+  }
+
+  public static boolean filterEquals(ClassFilter[] filters1, ClassFilter[] filters2) {
+    if (filters1.length != filters2.length) {
+      return false;
+    }
+    final Set<ClassFilter> f1 = new HashSet<ClassFilter>(Math.max((int) (filters1.length/.75f) + 1, 16));
+    final Set<ClassFilter> f2 = new HashSet<ClassFilter>(Math.max((int) (filters2.length/.75f) + 1, 16));
+    for (ClassFilter filter : filters1) {
+      f1.add(filter);
+    }
+    for (ClassFilter aFilters2 : filters2) {
+      f2.add(aFilters2);
+    }
+    return f2.equals(f1);
+  }
+
+  private static boolean elementListsEqual(List<Element> l1, List<Element> l2) {
+    if(l1 == null) return l2 == null;
+    if(l2 == null) return false;
+
+    if(l1.size() != l2.size()) return false;
+
+    Iterator<Element> i1 = l1.iterator();
+    Iterator<Element> i2 = l2.iterator();
+
+    while (i2.hasNext()) {
+      Element elem1 = i1.next();
+      Element elem2 = i2.next();
+
+      if(!elementsEqual(elem1, elem2)) return false;
+    }
+    return true;
+  }
+
+  private static boolean attributeListsEqual(List<Attribute> l1, List<Attribute> l2) {
+    if(l1 == null) return l2 == null;
+    if(l2 == null) return false;
+
+    if(l1.size() != l2.size()) return false;
+
+    Iterator<Attribute> i1 = l1.iterator();
+    Iterator<Attribute> i2 = l2.iterator();
+
+    while (i2.hasNext()) {
+      Attribute attr1 = i1.next();
+      Attribute attr2 = i2.next();
+
+      if (!Comparing.equal(attr1.getName(), attr2.getName()) || !Comparing.equal(attr1.getValue(), attr2.getValue())) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  public static boolean elementsEqual(Element e1, Element e2) {
+    if(e1 == null) {
+      return e2 == null;
+    }
+    if (!Comparing.equal(e1.getName(), e2.getName())) {
+      return false;
+    }
+    if (!elementListsEqual  ((List<Element>)e1.getChildren(), (List<Element>)e2.getChildren())) {
+      return false;
+    }
+    if (!attributeListsEqual((List<Attribute>)e1.getAttributes(), (List<Attribute>)e2.getAttributes())) {
+      return false;
+    }
+    return true;
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  public static boolean externalizableEqual(JDOMExternalizable  e1, JDOMExternalizable e2) {
+    Element root1 = new Element("root");
+    Element root2 = new Element("root");
+    try {
+      e1.writeExternal(root1);
+    }
+    catch (WriteExternalException e) {
+      LOG.debug(e);
+    }
+    try {
+      e2.writeExternal(root2);
+    }
+    catch (WriteExternalException e) {
+      LOG.debug(e);
+    }
+
+    return elementsEqual(root1, root2);
+  }
+
+  public static List<Pair<Breakpoint, Event>> getEventDescriptors(SuspendContextImpl suspendContext) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    if(suspendContext == null || suspendContext.getEventSet() == null) {
+      return Collections.emptyList();
+    }
+    final List<Pair<Breakpoint, Event>> eventDescriptors = new ArrayList<Pair<Breakpoint, Event>>();
+
+    final RequestManagerImpl requestManager = suspendContext.getDebugProcess().getRequestsManager();
+    for (final Event event : suspendContext.getEventSet()) {
+      Requestor requestor = requestManager.findRequestor(event.request());
+      if (requestor instanceof Breakpoint) {
+        eventDescriptors.add(new Pair<Breakpoint, Event>((Breakpoint)requestor, event));
+      }
+    }
+    return eventDescriptors;
+  }
+
+  public static TextWithImports getEditorText(final Editor editor) {
+    if (editor == null) {
+      return null;
+    }
+    final Project project = editor.getProject();
+    if (project == null) return null;
+
+    String defaultExpression = editor.getSelectionModel().getSelectedText();
+    if (defaultExpression == null) {
+      int offset = editor.getCaretModel().getOffset();
+      PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
+      if (psiFile != null) {
+        PsiElement elementAtCursor = psiFile.findElementAt(offset);
+        if (elementAtCursor != null) {
+          final EditorTextProvider textProvider = EditorTextProvider.EP.forLanguage(elementAtCursor.getLanguage());
+          if (textProvider != null) {
+            final TextWithImports editorText = textProvider.getEditorText(elementAtCursor);
+            if (editorText != null) return editorText;
+          }
+        }
+      }
+    }
+    else {
+      return new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, defaultExpression);
+    }
+    return null;
+  }
+
+  public abstract DebuggerTreeNode  getSelectedNode    (DataContext context);
+
+  public abstract EvaluatorBuilder  getEvaluatorBuilder();
+
+  public abstract CompletionEditor createEditor(Project project, PsiElement context, @NonNls String recentsId);
+
+  @Nullable
+  public static CodeFragmentFactory getEffectiveCodeFragmentFactory(final PsiElement psiContext) {
+    final CodeFragmentFactory factory = ApplicationManager.getApplication().runReadAction(new Computable<CodeFragmentFactory>() {
+      public CodeFragmentFactory compute() {
+        final List<CodeFragmentFactory> codeFragmentFactories = getCodeFragmentFactories(psiContext);
+        // the list always contains at least DefaultCodeFragmentFactory
+        return codeFragmentFactories.get(0);
+      }
+    });
+    return factory != null? new CodeFragmentFactoryContextWrapper(factory) : null;
+  }
+
+  private static class SigReader {
+    final String buffer;
+    int pos = 0;
+
+    SigReader(String s) {
+      buffer = s;
+    }
+
+    int get() {
+      return buffer.charAt(pos++);
+    }
+
+    int peek() {
+      return buffer.charAt(pos);
+    }
+
+    boolean eof() {
+      return buffer.length() <= pos;
+    }
+
+    @NonNls String getSignature() {
+      if (eof()) return "";
+
+      switch (get()) {
+        case 'Z':
+          return "boolean";
+        case 'B':
+          return "byte";
+        case 'C':
+          return "char";
+        case 'S':
+          return "short";
+        case 'I':
+          return "int";
+        case 'J':
+          return "long";
+        case 'F':
+          return "float";
+        case 'D':
+          return "double";
+        case 'V':
+          return "void";
+        case 'L':
+          int start = pos;
+          pos = buffer.indexOf(';', start) + 1;
+          LOG.assertTrue(pos > 0);
+          return buffer.substring(start, pos - 1).replace('/', '.');
+        case '[':
+          return getSignature() + "[]";
+        case '(':
+          StringBuffer result = new StringBuffer("(");
+          String separator = "";
+          while (peek() != ')') {
+            result.append(separator);
+            result.append(getSignature());
+            separator = ", ";
+          }
+          get();
+          result.append(")");
+          return getSignature() + " " + getClassName() + "." + getMethodName() + " " + result;
+        default:
+//          LOG.assertTrue(false, "unknown signature " + buffer);
+          return null;
+      }
+    }
+
+    String getMethodName() {
+      return "";
+    }
+
+    String getClassName() {
+      return "";
+    }
+  }
+
+  public static String methodName(final Method m) {
+    return methodName(signatureToName(m.declaringType().signature()), m.name(), m.signature());
+  }
+
+  public static String methodName(final String className, final String methodName, final String signature) {
+    try {
+      return new SigReader(signature) {
+        String getMethodName() {
+          return methodName;
+        }
+
+        String getClassName() {
+          return className;
+        }
+      }.getSignature();
+    }
+    catch (Exception e) {
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("Internal error : unknown signature" + signature);
+      }
+      return className + "." + methodName;
+    }
+  }
+
+  public static String signatureToName(String s) {
+    return new SigReader(s).getSignature();
+  }
+
+  public static Value createValue(VirtualMachineProxyImpl vm, String expectedType, double value) {
+    if (PsiType.DOUBLE.getPresentableText().equals(expectedType)) {
+      return vm.mirrorOf(value);
+    }
+    if (PsiType.FLOAT.getPresentableText().equals(expectedType)) {
+      return vm.mirrorOf((float)value);
+    }
+    return createValue(vm, expectedType, (long)value);
+  }
+
+  public static Value createValue(VirtualMachineProxyImpl vm, String expectedType, long value) {
+    if (PsiType.LONG.getPresentableText().equals(expectedType)) {
+      return vm.mirrorOf(value);
+    }
+    if (PsiType.INT.getPresentableText().equals(expectedType)) {
+      return vm.mirrorOf((int)value);
+    }
+    if (PsiType.SHORT.getPresentableText().equals(expectedType)) {
+      return vm.mirrorOf((short)value);
+    }
+    if (PsiType.BYTE.getPresentableText().equals(expectedType)) {
+      return vm.mirrorOf((byte)value);
+    }
+    if (PsiType.CHAR.getPresentableText().equals(expectedType)) {
+      return vm.mirrorOf((char)value);
+    }
+    if (PsiType.DOUBLE.getPresentableText().equals(expectedType)) {
+      return vm.mirrorOf((double)value);
+    }
+    if (PsiType.FLOAT.getPresentableText().equals(expectedType)) {
+      return vm.mirrorOf((float)value);
+    }
+    return null;
+  }
+
+  public static Value createValue(VirtualMachineProxyImpl vm, String expectedType, boolean value) {
+    if (PsiType.BOOLEAN.getPresentableText().equals(expectedType)) {
+      return vm.mirrorOf(value);
+    }
+    return null;
+  }
+
+  public static Value createValue(VirtualMachineProxyImpl vm, String expectedType, char value) {
+    if (PsiType.CHAR.getPresentableText().equals(expectedType)) {
+      return vm.mirrorOf(value);
+    }
+    if (PsiType.LONG.getPresentableText().equals(expectedType)) {
+      return vm.mirrorOf((long)value);
+    }
+    if (PsiType.INT.getPresentableText().equals(expectedType)) {
+      return vm.mirrorOf((int)value);
+    }
+    if (PsiType.SHORT.getPresentableText().equals(expectedType)) {
+      return vm.mirrorOf((short)value);
+    }
+    if (PsiType.BYTE.getPresentableText().equals(expectedType)) {
+      return vm.mirrorOf((byte)value);
+    }
+    return null;
+  }
+
+  public static String truncateString(final String str) {
+    if (str.length() > MAX_LABEL_SIZE) {
+      return str.substring(0, MAX_LABEL_SIZE) + "...";
+    }
+    return str;
+  }
+
+  public static String getThreadStatusText(int statusId) {
+    switch (statusId) {
+      case ThreadReference.THREAD_STATUS_MONITOR:
+        return DebuggerBundle.message("status.thread.monitor");
+      case ThreadReference.THREAD_STATUS_NOT_STARTED:
+        return DebuggerBundle.message("status.thread.not.started");
+      case ThreadReference.THREAD_STATUS_RUNNING:
+        return DebuggerBundle.message("status.thread.running");
+      case ThreadReference.THREAD_STATUS_SLEEPING:
+        return DebuggerBundle.message("status.thread.sleeping");
+      case ThreadReference.THREAD_STATUS_UNKNOWN:
+        return DebuggerBundle.message("status.thread.unknown");
+      case ThreadReference.THREAD_STATUS_WAIT:
+        return DebuggerBundle.message("status.thread.wait");
+      case ThreadReference.THREAD_STATUS_ZOMBIE:
+        return DebuggerBundle.message("status.thread.zombie");
+      default:
+        return DebuggerBundle.message("status.thread.undefined");
+    }
+  }
+
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsImpl.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsImpl.java
new file mode 100644
index 0000000..269799d
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsImpl.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl;
+
+import com.intellij.debugger.actions.DebuggerAction;
+import com.intellij.debugger.apiAdapters.TransportServiceWrapper;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.StackFrameContext;
+import com.intellij.debugger.engine.evaluation.*;
+import com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilder;
+import com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilderImpl;
+import com.intellij.debugger.ui.CompletionEditor;
+import com.intellij.debugger.ui.DebuggerExpressionComboBox;
+import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeExpression;
+import com.intellij.debugger.ui.tree.DebuggerTreeNode;
+import com.intellij.execution.ExecutionException;
+import com.intellij.ide.util.TreeClassChooser;
+import com.intellij.ide.util.TreeClassChooserFactory;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.JDOMExternalizerUtil;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiExpression;
+import com.intellij.util.net.NetUtils;
+import com.sun.jdi.Value;
+import org.jdom.Element;
+
+import java.io.IOException;
+
+public class DebuggerUtilsImpl extends DebuggerUtilsEx{
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.impl.DebuggerUtilsImpl");
+
+  public PsiExpression substituteThis(PsiExpression expressionWithThis, PsiExpression howToEvaluateThis, Value howToEvaluateThisValue, StackFrameContext context)
+    throws EvaluateException {
+    return DebuggerTreeNodeExpression.substituteThis(expressionWithThis, howToEvaluateThis, howToEvaluateThisValue);
+  }
+
+  public EvaluatorBuilder getEvaluatorBuilder() {
+    return EvaluatorBuilderImpl.getInstance();
+  }
+
+  public DebuggerTreeNode getSelectedNode(DataContext context) {
+    return DebuggerAction.getSelectedNode(context);
+  }
+
+  public DebuggerContextImpl getDebuggerContext(DataContext context) {
+    return DebuggerAction.getDebuggerContext(context);
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  public Element writeTextWithImports(TextWithImports text) {
+    Element element = new Element("TextWithImports");
+
+    element.setAttribute("text", text.toExternalForm());
+    element.setAttribute("type", text.getKind() == CodeFragmentKind.EXPRESSION ? "expression" : "code fragment");
+    return element;
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  public TextWithImports readTextWithImports(Element element) {
+    LOG.assertTrue("TextWithImports".equals(element.getName()));
+
+    String text = element.getAttributeValue("text");
+    if ("expression".equals(element.getAttributeValue("type"))) {
+      return new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, text);
+    } else {
+      return new TextWithImportsImpl(CodeFragmentKind.CODE_BLOCK, text);
+    }
+  }
+
+  public void writeTextWithImports(Element root, String name, TextWithImports value) {
+    LOG.assertTrue(value.getKind() == CodeFragmentKind.EXPRESSION);
+    JDOMExternalizerUtil.writeField(root, name, value.toExternalForm());
+  }
+
+  public TextWithImports readTextWithImports(Element root, String name) {
+    String s = JDOMExternalizerUtil.readField(root, name);
+    if(s == null) return null;
+    return new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, s);
+  }
+
+  public TextWithImports createExpressionWithImports(String expression) {
+    return new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, expression);
+  }
+
+  public PsiElement getContextElement(StackFrameContext context) {
+    return PositionUtil.getContextElement(context);
+  }
+
+  public PsiClass chooseClassDialog(String title, Project project) {
+    TreeClassChooser dialog = TreeClassChooserFactory.getInstance(project).createAllProjectScopeChooser(title);
+    dialog.showDialog();
+    return dialog.getSelected();
+  }
+
+  public CompletionEditor createEditor(Project project, PsiElement context, String recentsId) {
+    return new DebuggerExpressionComboBox(project, context, recentsId, DefaultCodeFragmentFactory.getInstance());
+  }
+
+  public String findAvailableDebugAddress(final boolean useSockets) throws ExecutionException {
+    final TransportServiceWrapper transportService = TransportServiceWrapper.getTransportService(useSockets);
+
+    if(useSockets) {
+      final int freePort;
+      try {
+        freePort = NetUtils.findAvailableSocketPort();
+      }
+      catch (IOException e) {
+        throw new ExecutionException(DebugProcessImpl.processError(e));
+      }
+      return Integer.toString(freePort);
+    }
+
+    try {
+      String address  = transportService.startListening();
+      transportService.stopListening(address);
+      return address;
+    }
+    catch (IOException e) {
+      throw new ExecutionException(DebugProcessImpl.processError(e));
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/EditorTextProvider.java b/java/debugger/impl/src/com/intellij/debugger/impl/EditorTextProvider.java
new file mode 100644
index 0000000..1667b74
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/EditorTextProvider.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2000-2011 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.debugger.impl;
+
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.lang.LanguageExtension;
+import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.PsiElement;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Provides text in the editor for Evaluate expression action
+ * @author Maxim.Medvedev
+ */
+public interface EditorTextProvider {
+  LanguageExtension<EditorTextProvider> EP = new LanguageExtension<EditorTextProvider>("com.intellij.debuggerEditorTextProvider");
+
+  @Nullable
+  TextWithImports getEditorText(PsiElement elementAtCaret);
+
+  @Nullable
+  Pair<PsiElement, TextRange> findExpression(PsiElement elementAtCaret, boolean allowMethodCalls);
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/EventQueue.java b/java/debugger/impl/src/com/intellij/debugger/impl/EventQueue.java
new file mode 100644
index 0000000..a7bd73a
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/EventQueue.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl;
+
+import com.intellij.openapi.diagnostic.Logger;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+
+public class EventQueue<E> {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.impl.EventQueue");
+
+  private final LinkedList[] myEvents;
+  private final ReentrantLock myLock;
+  private final Condition myEventsAvailable;
+
+  private volatile E myCurrentEvent;
+
+  private volatile boolean myIsClosed = false;
+
+  public EventQueue (int countPriorities) {
+    myLock = new ReentrantLock();
+    myEventsAvailable = myLock.newCondition();
+    myEvents = new LinkedList[countPriorities];
+    for (int i = 0; i < myEvents.length; i++) {
+      myEvents[i] = new LinkedList<E>();
+    }
+  }
+
+  public boolean pushBack(@NotNull E event, int priority) {
+    if(LOG.isDebugEnabled()) {
+      LOG.debug("pushBack event " + event);
+    }
+
+    myLock.lock();
+    try {
+      if (isClosed()) {
+        return false;
+      }
+      getEventsList(priority).addFirst(event);
+      myEventsAvailable.signalAll();
+    }
+    finally {
+      myLock.unlock();
+    }
+    return true;
+  }
+
+  public boolean put(@NotNull E event, int priority) {
+    if(LOG.isDebugEnabled()) {
+      LOG.debug("put event " + event);
+    }
+
+    myLock.lock();
+    try {
+      if (isClosed()) {
+        return false;
+      }
+      getEventsList(priority).offer(event);
+      myEventsAvailable.signalAll();
+    }
+    finally {
+      myLock.unlock();
+    }
+    return true;
+  }
+
+  private LinkedList<E> getEventsList(final int priority) {
+    return (LinkedList<E>)myEvents[priority];
+  }
+
+  public void close(){
+    myLock.lock();
+    try {
+      myIsClosed = true;
+      myEventsAvailable.signalAll();
+    }
+    finally {
+      myLock.unlock();
+    }
+  }
+
+  private E getEvent() throws EventQueueClosedException {
+    myLock.lock();
+    try {
+      while (true) {
+        if(myIsClosed) {
+          throw new EventQueueClosedException();
+        }
+        for (int i = 0; i < myEvents.length; i++) {
+          final E event = getEventsList(i).poll();
+          if (event != null) {
+            return event;
+          }
+        }
+        myEventsAvailable.awaitUninterruptibly();
+      }
+    }
+    finally {
+      myLock.unlock();
+    }
+  }
+
+  public E get() throws EventQueueClosedException {
+    try {
+      return myCurrentEvent = getEvent();
+    }
+    catch (EventQueueClosedException e) {
+      myCurrentEvent = null; // cleanup
+      throw e;
+    }
+  }
+
+  public boolean isClosed() {
+    return myIsClosed;
+  }
+
+  public E getCurrentEvent() {
+    return myCurrentEvent;
+  }
+
+  public List<E> clearQueue() {
+    final List<E> allEvents = new ArrayList<E>();
+    for (int i = 0; i < myEvents.length; i++) {
+      final LinkedList<E> eventList = getEventsList(i);
+      while (!eventList.isEmpty()) {
+        allEvents.add(eventList.poll());
+      }
+    }
+    return allEvents;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/EventQueueClosedException.java b/java/debugger/impl/src/com/intellij/debugger/impl/EventQueueClosedException.java
new file mode 100644
index 0000000..d58b663
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/EventQueueClosedException.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl;
+
+/**
+ * @author lex
+ */
+public class EventQueueClosedException extends Exception {
+  @Override
+  public Throwable fillInStackTrace() {
+    return this;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/GenericDebuggerParametersRunnerConfigurable.java b/java/debugger/impl/src/com/intellij/debugger/impl/GenericDebuggerParametersRunnerConfigurable.java
new file mode 100644
index 0000000..b0cb440
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/GenericDebuggerParametersRunnerConfigurable.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.DebuggerUtils;
+import com.intellij.debugger.settings.DebuggerSettings;
+import com.intellij.execution.ExecutionException;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.options.ConfigurationException;
+import com.intellij.openapi.options.SettingsEditor;
+import com.intellij.openapi.options.ShowSettingsUtil;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.xdebugger.impl.settings.DebuggerConfigurable;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+public class GenericDebuggerParametersRunnerConfigurable extends SettingsEditor<GenericDebuggerRunnerSettings> {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.impl.GenericDebuggerParametersRunnerConfigurable");
+  private JPanel myPanel;
+  private JTextField myAddressField;
+  private JPanel myShMemPanel;
+  private JPanel myPortPanel;
+  private JTextField myPortField;
+  private boolean myIsLocal = false;
+  private JButton myDebuggerSettings;
+  private JRadioButton mySocketTransport;
+  private JRadioButton myShmemTransport;
+  private JPanel myTransportPanel;
+
+  public GenericDebuggerParametersRunnerConfigurable(final Project project) {
+    myDebuggerSettings.addActionListener(new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        ShowSettingsUtil.getInstance().showSettingsDialog(project, DebuggerConfigurable.DISPLAY_NAME);
+        if (myIsLocal) {
+          setTransport(DebuggerSettings.getInstance().DEBUGGER_TRANSPORT);
+        }
+        suggestAvailablePortIfNotSpecified();
+        updateUI();
+      }
+    });
+
+    final ActionListener listener = new ActionListener() {
+      public void actionPerformed(final ActionEvent e) {
+        suggestAvailablePortIfNotSpecified();
+        updateUI();
+        myPanel.repaint();
+      }
+    };
+    mySocketTransport.addActionListener(listener);
+    myShmemTransport.addActionListener(listener);
+
+    updateUI();
+
+    myTransportPanel.setVisible(false);
+
+    ButtonGroup group = new ButtonGroup();
+    group.add(mySocketTransport);
+    group.add(myShmemTransport);
+  }
+
+  private boolean isSocket() {
+    return getTransport() == DebuggerSettings.SOCKET_TRANSPORT;
+  }
+
+  @NotNull
+  public JComponent createEditor() {
+    return myPanel;
+  }
+
+  private void updateUI() {
+    myPortPanel.setVisible(isSocket());
+    myShMemPanel.setVisible(!isSocket());
+    myAddressField.setEditable(!myIsLocal);
+    myPortField.setEditable(!myIsLocal);
+    mySocketTransport.setEnabled(!myIsLocal);
+    myShmemTransport.setEnabled(!myIsLocal);
+  }
+
+  public void disposeEditor() {
+  }
+
+  public void resetEditorFrom(GenericDebuggerRunnerSettings runnerSettings) {
+    setIsLocal(runnerSettings.LOCAL);
+    setTransport(runnerSettings.getTransport());
+    setPort(StringUtil.notNullize(runnerSettings.getDebugPort()));
+    suggestAvailablePortIfNotSpecified();
+    updateUI();
+  }
+
+  private void suggestAvailablePortIfNotSpecified() {
+    String port = getPort();
+    boolean portSpecified = !StringUtil.isEmpty(port);
+    boolean isSocketTransport = getTransport() == DebuggerSettings.SOCKET_TRANSPORT;
+    if (isSocketTransport) {
+      try {
+        Integer.parseInt(port);
+      }
+      catch (NumberFormatException e) {
+        portSpecified = false;
+      }
+    }
+
+    if (!portSpecified) {
+      try {
+        setPort(DebuggerUtils.getInstance().findAvailableDebugAddress(isSocketTransport));
+      }
+      catch (ExecutionException e) {
+        LOG.info(e);
+      }
+    }
+  }
+
+  private int getTransport() {
+    if(myIsLocal) {
+      return DebuggerSettings.getInstance().DEBUGGER_TRANSPORT;
+    }
+    else {
+      return mySocketTransport.isSelected() ? DebuggerSettings.SOCKET_TRANSPORT : DebuggerSettings.SHMEM_TRANSPORT;
+    }
+  }
+
+  private String getPort() {
+    if (isSocket()) {
+      return myPortField.getText();
+    }
+    else {
+      return myAddressField.getText();
+    }
+  }
+
+  private void checkPort() throws ConfigurationException {
+    if (isSocket() && myPortField.getText().length() > 0) {
+      try {
+        final int port = Integer.parseInt(myPortField.getText());
+        if (port < 0 || port > 0xffff) {
+          throw new NumberFormatException();
+        }
+      }
+      catch (NumberFormatException e) {
+        throw new ConfigurationException(DebuggerBundle.message("error.text.invalid.port.0", myPortField.getText()));
+      }
+    }
+  }
+
+  private void setTransport(int transport) {
+    mySocketTransport.setSelected(transport == DebuggerSettings.SOCKET_TRANSPORT);
+    myShmemTransport.setSelected(transport != DebuggerSettings.SOCKET_TRANSPORT);
+  }
+
+  private void setIsLocal(boolean b) {
+    myTransportPanel.setVisible(true);
+    myDebuggerSettings.setVisible(b);
+    myIsLocal = b;
+  }
+
+  private void setPort(String port) {
+    if (isSocket()) {
+      myPortField.setText(port);
+    }
+    else {
+      myAddressField.setText(port);
+    }
+  }
+
+  public void applyEditorTo(GenericDebuggerRunnerSettings runnerSettings) throws ConfigurationException {
+    runnerSettings.LOCAL = myIsLocal;
+    checkPort();
+    runnerSettings.setDebugPort(getPort());
+    if (!myIsLocal) {
+      runnerSettings.setTransport(getTransport());
+    }
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/GenericDebuggerRunner.java b/java/debugger/impl/src/com/intellij/debugger/impl/GenericDebuggerRunner.java
new file mode 100644
index 0000000..fd25d96
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/GenericDebuggerRunner.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl;
+
+import com.intellij.debugger.engine.DebuggerUtils;
+import com.intellij.debugger.settings.DebuggerSettings;
+import com.intellij.debugger.ui.DebuggerPanelsManager;
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.Executor;
+import com.intellij.execution.configurations.*;
+import com.intellij.execution.executors.DefaultDebugExecutor;
+import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.execution.runners.JavaPatchableProgramRunner;
+import com.intellij.execution.ui.RunContentDescriptor;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.options.SettingsEditor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.text.StringUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class GenericDebuggerRunner extends JavaPatchableProgramRunner<GenericDebuggerRunnerSettings> {
+  public boolean canRun(@NotNull final String executorId, @NotNull final RunProfile profile) {
+    return executorId.equals(DefaultDebugExecutor.EXECUTOR_ID) && profile instanceof ModuleRunProfile
+           && !(profile instanceof RunConfigurationWithSuppressedDefaultDebugAction);
+  }
+
+  @NotNull
+  public String getRunnerId() {
+    return DebuggingRunnerData.DEBUGGER_RUNNER_ID;
+  }
+
+  protected RunContentDescriptor doExecute(final Project project, final Executor executor, final RunProfileState state, final RunContentDescriptor contentToReuse,
+                                           final ExecutionEnvironment env) throws ExecutionException {
+    FileDocumentManager.getInstance().saveAllDocuments();
+    return createContentDescriptor(project, executor, state, contentToReuse, env);
+  }
+
+  @Nullable
+  protected RunContentDescriptor createContentDescriptor(Project project, Executor executor, RunProfileState state,
+                                                         RunContentDescriptor contentToReuse,
+                                                         ExecutionEnvironment env) throws ExecutionException {
+    if (state instanceof JavaCommandLine) {
+      final JavaParameters parameters = ((JavaCommandLine)state).getJavaParameters();
+      runCustomPatchers(parameters, state.getRunnerSettings(), executor);
+      RemoteConnection connection = DebuggerManagerImpl.createDebugParameters(parameters, true, DebuggerSettings.getInstance().DEBUGGER_TRANSPORT, "", false);
+      return attachVirtualMachine(project, executor, state, contentToReuse, env, connection, true);
+    }
+    if (state instanceof PatchedRunnableState) {
+      final RemoteConnection connection = doPatch(new JavaParameters(), state.getRunnerSettings());
+      return attachVirtualMachine(project, executor, state, contentToReuse, env, connection, true);
+    }
+    if (state instanceof RemoteState) {
+      final RemoteConnection connection = createRemoteDebugConnection((RemoteState)state, state.getRunnerSettings());
+      return attachVirtualMachine(project, executor, state, contentToReuse, env, connection, false);
+    }
+
+    return null;
+  }
+
+  @Nullable
+  protected RunContentDescriptor attachVirtualMachine(Project project, Executor executor, RunProfileState state,
+                                                      RunContentDescriptor contentToReuse,
+                                                      ExecutionEnvironment env, RemoteConnection connection, boolean pollConnection)
+    throws ExecutionException {
+    final DebuggerPanelsManager manager = DebuggerPanelsManager.getInstance(project);
+    return manager.attachVirtualMachine(executor, this, env, state, contentToReuse, connection, pollConnection);
+  }
+
+  private static RemoteConnection createRemoteDebugConnection(RemoteState connection, final RunnerSettings settings) {
+    final RemoteConnection remoteConnection = connection.getRemoteConnection();
+
+    GenericDebuggerRunnerSettings debuggerRunnerSettings = ((GenericDebuggerRunnerSettings)settings.getData());
+
+    if (debuggerRunnerSettings != null) {
+      remoteConnection.setUseSockets(debuggerRunnerSettings.getTransport() == DebuggerSettings.SOCKET_TRANSPORT);
+      remoteConnection.setAddress(debuggerRunnerSettings.DEBUG_PORT);
+    }
+
+    return remoteConnection;
+  }
+
+  public GenericDebuggerRunnerSettings createConfigurationData(ConfigurationInfoProvider settingsProvider) {
+    return new GenericDebuggerRunnerSettings();
+  }
+
+  public void patch(JavaParameters javaParameters, RunnerSettings settings, final boolean beforeExecution) throws ExecutionException {
+    doPatch(javaParameters, settings);
+    runCustomPatchers(javaParameters, settings, Executor.EXECUTOR_EXTENSION_NAME.findExtension(DefaultDebugExecutor.class));
+  }
+
+  private static RemoteConnection doPatch(final JavaParameters javaParameters, final RunnerSettings settings) throws ExecutionException {
+    final GenericDebuggerRunnerSettings debuggerSettings = ((GenericDebuggerRunnerSettings)settings.getData());
+    if (StringUtil.isEmpty(debuggerSettings.getDebugPort())) {
+      debuggerSettings.setDebugPort(DebuggerUtils.getInstance().findAvailableDebugAddress(debuggerSettings.getTransport() == DebuggerSettings.SOCKET_TRANSPORT));
+    }
+    return DebuggerManagerImpl.createDebugParameters(javaParameters, debuggerSettings, false);
+  }
+
+  public SettingsEditor<GenericDebuggerRunnerSettings> getSettingsEditor(final Executor executor, RunConfiguration configuration) {
+    if (configuration instanceof RunConfigurationWithRunnerSettings) {
+      if (((RunConfigurationWithRunnerSettings)configuration).isSettingsNeeded()) {
+        return new GenericDebuggerParametersRunnerConfigurable(configuration.getProject());
+      }
+    }
+    return null;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/GenericDebuggerRunnerSettings.java b/java/debugger/impl/src/com/intellij/debugger/impl/GenericDebuggerRunnerSettings.java
new file mode 100644
index 0000000..b4a03c6
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/GenericDebuggerRunnerSettings.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl;
+
+import com.intellij.debugger.settings.DebuggerSettings;
+import com.intellij.execution.configurations.DebuggingRunnerData;
+import com.intellij.openapi.util.DefaultJDOMExternalizer;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.JDOMExternalizable;
+import com.intellij.openapi.util.WriteExternalException;
+import org.jdom.Element;
+
+public class GenericDebuggerRunnerSettings implements JDOMExternalizable, DebuggingRunnerData {
+  public String DEBUG_PORT = "";
+  public int TRANSPORT = DebuggerSettings.SOCKET_TRANSPORT;
+  public boolean LOCAL = true;
+
+  public GenericDebuggerRunnerSettings() {
+  }
+
+  public String getDebugPort() {
+    return DEBUG_PORT;
+  }
+
+  public boolean isRemote() {
+    return !LOCAL;
+  }
+
+  public void setLocal(boolean isLocal) {
+    LOCAL = isLocal;
+  }
+
+  public void setDebugPort(String port) {
+    DEBUG_PORT = port;
+  }
+
+  public void setTransport(int transport) {
+    TRANSPORT = transport;
+  }
+
+  public void readExternal(Element element) throws InvalidDataException {
+    DefaultJDOMExternalizer.readExternal(this, element);
+  }
+
+  public void writeExternal(Element element) throws WriteExternalException {
+    DefaultJDOMExternalizer.writeExternal(this, element);
+  }
+
+  public int getTransport() {
+    if (LOCAL) {
+      return DebuggerSettings.getInstance().DEBUGGER_TRANSPORT;
+    }
+    else {
+      return TRANSPORT;
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/HotSwapFile.java b/java/debugger/impl/src/com/intellij/debugger/impl/HotSwapFile.java
new file mode 100644
index 0000000..db0a0fb
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/HotSwapFile.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl;
+
+import java.io.File;
+
+/**
+ * User: lex
+ * Date: Nov 18, 2003
+ * Time: 2:23:38 PM
+ */
+public class HotSwapFile {
+  final File file;
+
+  public HotSwapFile(File file) {
+    this.file = file;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/HotSwapManager.java b/java/debugger/impl/src/com/intellij/debugger/impl/HotSwapManager.java
new file mode 100644
index 0000000..b7cd3f9
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/HotSwapManager.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
+import com.intellij.debugger.engine.events.DebuggerCommandImpl;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.compiler.ex.CompilerPathsEx;
+import com.intellij.openapi.components.AbstractProjectComponent;
+import com.intellij.openapi.fileTypes.StdFileTypes;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.OrderEnumerator;
+import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.SystemInfo;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.util.containers.HashMap;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class HotSwapManager extends AbstractProjectComponent {
+  private final Map<DebuggerSession, Long> myTimeStamps = new HashMap<DebuggerSession, Long>();
+  private static final String CLASS_EXTENSION = ".class";
+
+  public HotSwapManager(Project project, DebuggerManagerEx manager) {
+    super(project);
+    manager.addDebuggerManagerListener(new DebuggerManagerAdapter() {
+      public void sessionCreated(DebuggerSession session) {
+        myTimeStamps.put(session, Long.valueOf(System.currentTimeMillis()));
+      }
+
+      public void sessionRemoved(DebuggerSession session) {
+        myTimeStamps.remove(session);
+      }
+    });
+  }
+
+  @NotNull
+  public String getComponentName() {
+    return "HotSwapManager";
+  }
+
+  private long getTimeStamp(DebuggerSession session) {
+    Long tStamp = myTimeStamps.get(session);
+    return tStamp != null ? tStamp.longValue() : 0;
+  }
+
+  void setTimeStamp(DebuggerSession session, long tStamp) {
+    myTimeStamps.put(session, Long.valueOf(tStamp));
+  }
+
+  public Map<String, HotSwapFile> scanForModifiedClasses(final DebuggerSession session, final HotSwapProgress progress, final boolean scanWithVFS) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+
+    final long timeStamp = getTimeStamp(session);
+    final Map<String, HotSwapFile> modifiedClasses = new HashMap<String, HotSwapFile>();
+
+    if (scanWithVFS) {
+      ApplicationManager.getApplication().runReadAction(new Runnable() {
+        public void run() {
+          final List<VirtualFile> allDirs = OrderEnumerator.orderEntries(myProject).withoutSdk().withoutLibraries().getPathsList().getRootDirs();
+          CompilerPathsEx.visitFiles(allDirs, new CompilerPathsEx.FileVisitor() {
+            protected void acceptDirectory(final VirtualFile file, final String fileRoot, final String filePath) {
+              if (!progress.isCancelled()) {
+                progress.setText(DebuggerBundle.message("progress.hotswap.scanning.path", filePath));
+                super.acceptDirectory(file, fileRoot, filePath);
+              }
+            }
+
+            protected void acceptFile(VirtualFile file, String fileRoot, String filePath) {
+              if (progress.isCancelled()) {
+                return;
+              }
+              if (file.getTimeStamp() > timeStamp && StdFileTypes.CLASS.equals(file.getFileType())) {
+                //noinspection HardCodedStringLiteral
+                if (SystemInfo.isFileSystemCaseSensitive ? filePath.endsWith(CLASS_EXTENSION) : StringUtil.endsWithIgnoreCase(filePath, CLASS_EXTENSION)) {
+                  progress.setText(DebuggerBundle.message("progress.hotswap.scanning.path", filePath));
+                  //noinspection HardCodedStringLiteral
+                  final String qualifiedName = filePath.substring(fileRoot.length() + 1, filePath.length() - CLASS_EXTENSION.length()).replace('/', '.');
+                  modifiedClasses.put(qualifiedName, new HotSwapFile(new File(filePath)));
+                }
+              }
+            }
+          });
+        }
+      });
+    }
+    else {
+      final List<File> outputRoots = new ArrayList<File>();
+      ApplicationManager.getApplication().runReadAction(new Runnable() {
+        public void run() {
+          final List<VirtualFile> allDirs = OrderEnumerator.orderEntries(myProject).withoutSdk().withoutLibraries().getPathsList().getRootDirs();
+          for (VirtualFile dir : allDirs) {
+            outputRoots.add(new File(dir.getPath()));
+          }
+        }
+      });
+      for (File root : outputRoots) {
+        final String rootPath = FileUtil.toCanonicalPath(root.getPath());
+        collectModifiedClasses(root, rootPath, rootPath + "/", modifiedClasses, progress, timeStamp);
+      }
+    }
+
+
+    return modifiedClasses;
+  }
+
+  private static boolean collectModifiedClasses(File file, String filePath, String rootPath, Map<String, HotSwapFile> container, HotSwapProgress progress, long timeStamp) {
+    if (progress.isCancelled()) {
+      return false;
+    }
+    final File[] files = file.listFiles();
+    if (files != null) {
+      for (File child : files) {
+        if (!collectModifiedClasses(child, filePath + "/" + child.getName(), rootPath, container, progress, timeStamp)) {
+          return false;
+        }
+      }
+    }
+    else { // not a dir
+      if (SystemInfo.isFileSystemCaseSensitive? StringUtil.endsWith(filePath, CLASS_EXTENSION) : StringUtil.endsWithIgnoreCase(filePath, CLASS_EXTENSION)) {
+        if (file.lastModified() > timeStamp) {
+          progress.setText(DebuggerBundle.message("progress.hotswap.scanning.path", filePath));
+          //noinspection HardCodedStringLiteral
+          final String qualifiedName = filePath.substring(rootPath.length(), filePath.length() - CLASS_EXTENSION.length()).replace('/', '.');
+          container.put(qualifiedName, new HotSwapFile(file));
+        }
+      }
+    }
+    return true;
+  }
+
+  public static HotSwapManager getInstance(Project project) {
+    return project.getComponent(HotSwapManager.class);
+  }
+
+  private void reloadClasses(DebuggerSession session, Map<String, HotSwapFile> classesToReload, HotSwapProgress progress) {
+    final long newSwapTime = System.currentTimeMillis();
+    new ReloadClassesWorker(session, progress).reloadClasses(classesToReload);
+    setTimeStamp(session, newSwapTime);
+  }
+
+  public static Map<DebuggerSession, Map<String, HotSwapFile>> findModifiedClasses(List<DebuggerSession> sessions, Map<String, List<String>> generatedPaths) {
+    final Map<DebuggerSession, Map<String, HotSwapFile>> result = new java.util.HashMap<DebuggerSession, Map<String, HotSwapFile>>();
+    List<Pair<DebuggerSession, Long>> sessionWithStamps = new ArrayList<Pair<DebuggerSession, Long>>();
+    for (DebuggerSession session : sessions) {
+      sessionWithStamps.add(new Pair<DebuggerSession, Long>(session, getInstance(session.getProject()).getTimeStamp(session)));
+    }
+    for (Map.Entry<String, List<String>> entry : generatedPaths.entrySet()) {
+      final File root = new File(entry.getKey());
+      for (String relativePath : entry.getValue()) {
+        if (SystemInfo.isFileSystemCaseSensitive? StringUtil.endsWith(relativePath, CLASS_EXTENSION) : StringUtil.endsWithIgnoreCase(relativePath, CLASS_EXTENSION)) {
+          final String qualifiedName = relativePath.substring(0, relativePath.length() - CLASS_EXTENSION.length()).replace('/', '.');
+          final HotSwapFile hotswapFile = new HotSwapFile(new File(root, relativePath));
+          final long fileStamp = hotswapFile.file.lastModified();
+
+          for (Pair<DebuggerSession, Long> pair : sessionWithStamps) {
+            final DebuggerSession session = pair.first;
+            if (fileStamp > pair.second) {
+              Map<String, HotSwapFile> container = result.get(session);
+              if (container == null) {
+                container = new java.util.HashMap<String, HotSwapFile>();
+                result.put(session, container);
+              }
+              container.put(qualifiedName, hotswapFile);
+            }
+          }
+        }
+      }
+    }
+    return result;
+  }
+
+
+  public static Map<DebuggerSession, Map<String, HotSwapFile>> scanForModifiedClasses(final List<DebuggerSession> sessions, final HotSwapProgress swapProgress, final boolean scanWithVFS) {
+    final Map<DebuggerSession, Map<String, HotSwapFile>> modifiedClasses = new HashMap<DebuggerSession, Map<String, HotSwapFile>>();
+
+    final MultiProcessCommand scanClassesCommand = new MultiProcessCommand();
+
+    swapProgress.setCancelWorker(new Runnable() {
+      public void run() {
+        scanClassesCommand.cancel();
+      }
+    });
+
+    for (final DebuggerSession debuggerSession : sessions) {
+      if (debuggerSession.isAttached()) {
+        scanClassesCommand.addCommand(debuggerSession.getProcess(), new DebuggerCommandImpl() {
+          protected void action() throws Exception {
+            swapProgress.setDebuggerSession(debuggerSession);
+            final Map<String, HotSwapFile> sessionClasses = getInstance(swapProgress.getProject()).scanForModifiedClasses(debuggerSession, swapProgress, scanWithVFS);
+            if (!sessionClasses.isEmpty()) {
+              modifiedClasses.put(debuggerSession, sessionClasses);
+            }
+          }
+        });
+      }
+    }
+
+    swapProgress.setTitle(DebuggerBundle.message("progress.hotswap.scanning.classes"));
+    scanClassesCommand.run();
+
+    return swapProgress.isCancelled() ? new HashMap<DebuggerSession, Map<String, HotSwapFile>>() : modifiedClasses;
+  }
+
+  public static void reloadModifiedClasses(final Map<DebuggerSession, Map<String, HotSwapFile>> modifiedClasses, final HotSwapProgress reloadClassesProgress) {
+    final MultiProcessCommand reloadClassesCommand = new MultiProcessCommand();
+
+    reloadClassesProgress.setCancelWorker(new Runnable() {
+      public void run() {
+        reloadClassesCommand.cancel();
+      }
+    });
+
+    for (final DebuggerSession debuggerSession : modifiedClasses.keySet()) {
+      reloadClassesCommand.addCommand(debuggerSession.getProcess(), new DebuggerCommandImpl() {
+        protected void action() throws Exception {
+          reloadClassesProgress.setDebuggerSession(debuggerSession);
+          getInstance(reloadClassesProgress.getProject()).reloadClasses(
+            debuggerSession, modifiedClasses.get(debuggerSession), reloadClassesProgress
+          );
+        }
+      });
+    }
+
+    reloadClassesProgress.setTitle(DebuggerBundle.message("progress.hotswap.reloading"));
+    reloadClassesCommand.run();
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/HotSwapProgress.java b/java/debugger/impl/src/com/intellij/debugger/impl/HotSwapProgress.java
new file mode 100644
index 0000000..55b3fe1
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/HotSwapProgress.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl;
+
+import com.intellij.openapi.project.Project;
+
+/**
+ * User: lex
+ * Date: Nov 18, 2003
+ * Time: 2:20:18 PM
+ */
+public abstract class HotSwapProgress {
+  private final Project myProject;
+  private Runnable myCancelWorker;
+  private volatile boolean myIsCancelled;
+
+  public HotSwapProgress(Project project) {
+    myProject = project;
+  }
+
+  public Project getProject() {
+    return myProject;
+  }
+
+  public abstract void addMessage(DebuggerSession session, final int type, final String text);
+
+  public abstract void setText(String text);
+
+  public abstract void setTitle(String title);
+
+  public abstract void setFraction(double v);
+
+  public void setCancelWorker(Runnable cancel) {
+    myCancelWorker = cancel;
+  }
+
+  public void cancel() {
+    myIsCancelled = true;
+    if(myCancelWorker != null) {
+      myCancelWorker.run();
+    }
+  }
+
+  public void finished() {    
+  }
+
+  public abstract void setDebuggerSession(DebuggerSession debuggerSession);
+
+  public boolean isCancelled() {
+    return myIsCancelled;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/InvokeAndWaitThread.java b/java/debugger/impl/src/com/intellij/debugger/impl/InvokeAndWaitThread.java
new file mode 100644
index 0000000..3576c86
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/InvokeAndWaitThread.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl;
+
+/**
+ * @author lex
+ */
+public abstract class InvokeAndWaitThread<E extends DebuggerTask> extends InvokeThread<E> {
+
+  public InvokeAndWaitThread() {
+    super();
+  }
+
+  /**
+   * !!! Do not remove this code !!!
+   * Otherwise it will be impossible to override schedule method
+   */
+  public boolean schedule(E e) {
+    return super.schedule(e);
+  }
+
+  public boolean pushBack(E e) {
+    return super.pushBack(e);
+  }
+
+  public void invokeAndWait(final E runnable) {
+    runnable.hold();
+    schedule(runnable);
+    runnable.waitFor();
+  }
+}
+
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/InvokeThread.java b/java/debugger/impl/src/com/intellij/debugger/impl/InvokeThread.java
new file mode 100644
index 0000000..84ed730
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/InvokeThread.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl;
+
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.sun.jdi.VMDisconnectedException;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+import java.util.concurrent.*;
+
+/**
+ * @author lex
+ */
+public abstract class InvokeThread<E extends PrioritizedTask> {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.impl.InvokeThread");
+
+  private static final ThreadLocal<WorkerThreadRequest> ourWorkerRequest = new ThreadLocal<WorkerThreadRequest>();
+
+  public static final class WorkerThreadRequest<E extends PrioritizedTask> implements Runnable {
+    private final InvokeThread<E> myOwner;
+    private volatile Future<?> myRequestFuture;
+
+    WorkerThreadRequest(InvokeThread<E> owner) {
+      myOwner = owner;
+    }
+
+    public void run() {
+      synchronized (this) {
+        while (myRequestFuture == null) {
+          try {
+            wait();
+          }
+          catch (InterruptedException ignore) {
+          }
+        }
+      }
+      ourWorkerRequest.set(this);
+      try {
+        myOwner.run(this);
+      } 
+      finally {
+        ourWorkerRequest.set(null);
+        boolean b = Thread.interrupted(); // reset interrupted status to return into pool
+      }
+    }
+
+    public void interrupt() {
+      assert myRequestFuture != null;
+      myRequestFuture.cancel( true );  
+    }
+
+    public boolean isInterrupted() {
+      assert myRequestFuture != null;
+      return myRequestFuture.isCancelled() || myRequestFuture.isDone();
+    }
+
+    public void join() throws InterruptedException, ExecutionException {
+      assert myRequestFuture != null;
+      try {
+        myRequestFuture.get();
+      }
+      catch(CancellationException ignored) {
+      }
+    }
+
+    public void join(long timeout) throws InterruptedException, ExecutionException {
+      assert myRequestFuture != null;
+      try {
+        myRequestFuture.get(timeout, TimeUnit.MILLISECONDS);
+      }
+      catch (TimeoutException ignored) {
+      } 
+      catch (CancellationException ignored) {
+      }
+    }
+
+    final void setRequestFuture(Future<?> requestFuture) {
+      synchronized (this) {
+        myRequestFuture = requestFuture;
+        notifyAll();
+      }
+    }
+
+    public InvokeThread<E> getOwner() {
+      return myOwner;
+    }
+
+    public boolean isDone() {
+      assert myRequestFuture != null;
+      return myRequestFuture.isDone() && ourWorkerRequest.get() == null;
+    }
+  }
+
+  protected final EventQueue<E> myEvents;
+
+  private volatile WorkerThreadRequest myCurrentRequest = null;
+
+  public InvokeThread() {
+    myEvents = new EventQueue<E>(PrioritizedTask.Priority.values().length);
+    startNewWorkerThread();
+  }
+
+  protected abstract void processEvent(E e);
+
+  protected void startNewWorkerThread() {
+    final WorkerThreadRequest workerRequest = new WorkerThreadRequest<E>(this);
+    myCurrentRequest = workerRequest;
+    workerRequest.setRequestFuture( ApplicationManager.getApplication().executeOnPooledThread(workerRequest) );
+  }
+
+  private void run(@NotNull WorkerThreadRequest threadRequest) {
+    while(true) {
+      try {
+        if(threadRequest.isInterrupted()) {
+          break;
+        }
+
+        final WorkerThreadRequest currentRequest = getCurrentRequest();
+        if(currentRequest != threadRequest) {
+          LOG.error("Expected " + threadRequest + " instead of " + currentRequest);
+          if (currentRequest != null && !currentRequest.isDone()) {
+            continue; // ensure events are processed by one thread at a time
+          }
+        }
+
+        processEvent(myEvents.get());
+      }
+      catch (VMDisconnectedException e) {
+        break;
+      }
+      catch (EventQueueClosedException e) {
+        final List<E> unprocessed = myEvents.clearQueue();
+        for (E event : unprocessed) {
+          try {
+            processEvent(event);
+          }
+          catch (Throwable ignored) {
+          }
+        }
+        break;
+      }
+      catch (RuntimeException e) {
+        if(e.getCause() instanceof InterruptedException) {
+          break;
+        }
+        LOG.error(e);
+      }
+      catch (Throwable e) {
+        LOG.error(e);
+      }
+    }
+
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("Request " + this.toString() + " exited");
+    }
+  }
+
+  protected static InvokeThread currentThread() {
+    final WorkerThreadRequest request = getCurrentThreadRequest();
+    return request != null? request.getOwner() : null;
+  }
+
+  public boolean schedule(E r) {
+    if(LOG.isDebugEnabled()) {
+      LOG.debug("schedule " + r + " in " + this);
+    }
+    return myEvents.put(r, r.getPriority().ordinal());
+  }
+
+  public boolean pushBack(E r) {
+    if(LOG.isDebugEnabled()) {
+      LOG.debug("pushBack " + r + " in " + this);
+    }
+    return myEvents.pushBack(r, r.getPriority().ordinal());
+  }
+
+  protected void switchToRequest(WorkerThreadRequest newWorkerThread) {
+    final WorkerThreadRequest request = getCurrentThreadRequest();
+    LOG.assertTrue(request != null);
+    myCurrentRequest = newWorkerThread;
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("Closing " + request + " new request = " + newWorkerThread);
+    }
+
+    request.interrupt();
+  }
+
+  public WorkerThreadRequest getCurrentRequest() {
+    return myCurrentRequest;
+  }
+
+  public static WorkerThreadRequest getCurrentThreadRequest() {
+    return ourWorkerRequest.get();
+  }
+
+  public void close() {
+    myEvents.close();
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("Closing evaluation");
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/JavaEditorTextProviderImpl.java b/java/debugger/impl/src/com/intellij/debugger/impl/JavaEditorTextProviderImpl.java
new file mode 100644
index 0000000..e97b4bf
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/JavaEditorTextProviderImpl.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2000-2011 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.debugger.impl;
+
+import com.intellij.debugger.engine.DebuggerUtils;
+import com.intellij.debugger.engine.evaluation.CodeFragmentKind;
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.debugger.engine.evaluation.TextWithImportsImpl;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.*;
+import com.intellij.util.IncorrectOperationException;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author Maxim.Medvedev
+ */
+public class JavaEditorTextProviderImpl implements EditorTextProvider {
+  private static final Logger LOG = Logger.getInstance(JavaEditorTextProviderImpl.class);
+
+  @Override
+  public TextWithImports getEditorText(PsiElement elementAtCaret) {
+    String result = null;
+    PsiElement element = findExpression(elementAtCaret);
+    if (element != null) {
+      if (element instanceof PsiReferenceExpression) {
+        final PsiReferenceExpression reference = (PsiReferenceExpression)element;
+        if (reference.getQualifier() == null) {
+          final PsiElement resolved = reference.resolve();
+          if (resolved instanceof PsiEnumConstant) {
+            final PsiEnumConstant enumConstant = (PsiEnumConstant)resolved;
+            final PsiClass enumClass = enumConstant.getContainingClass();
+            if (enumClass != null) {
+              result = enumClass.getName() + "." + enumConstant.getName();
+            }
+          }
+        }
+      }
+      if (result == null) {
+        result = element.getText();
+      }
+    }
+    return result != null? new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, result) : null;
+  }
+
+  @Nullable
+  private static PsiElement findExpression(PsiElement element) {
+    if (!(element instanceof PsiIdentifier || element instanceof PsiKeyword)) {
+      return null;
+    }
+    PsiElement parent = element.getParent();
+    if (parent instanceof PsiVariable) {
+      return element;
+    }
+    if (parent instanceof PsiReferenceExpression) {
+      if (parent.getParent() instanceof PsiCallExpression) return parent.getParent();
+      return parent;
+    }
+    if (parent instanceof PsiThisExpression) {
+      return parent;
+    }
+    return null;
+  }
+
+  @Nullable
+  public Pair<PsiElement, TextRange> findExpression(PsiElement element, boolean allowMethodCalls) {
+    if (!(element instanceof PsiIdentifier || element instanceof PsiKeyword)) {
+      return null;
+    }
+
+    PsiElement expression = null;
+    PsiElement parent = element.getParent();
+    if (parent instanceof PsiVariable) {
+      expression = element;
+    }
+    else if (parent instanceof PsiReferenceExpression) {
+      final PsiElement pparent = parent.getParent();
+      if (pparent instanceof PsiCallExpression) {
+        parent = pparent;
+      }
+      if (allowMethodCalls || !DebuggerUtils.hasSideEffects(parent)) {
+        expression = parent;
+      }
+    }
+    else if (parent instanceof PsiThisExpression) {
+      expression = parent;
+    }
+
+    if (expression != null) {
+      try {
+        PsiElement context = element;
+        if(parent instanceof PsiParameter) {
+          try {
+            context = ((PsiMethod)((PsiParameter)parent).getDeclarationScope()).getBody();
+          }
+          catch (Throwable ignored) {
+          }
+        }
+        else {
+          while(context != null  && !(context instanceof PsiStatement) && !(context instanceof PsiClass)) {
+            context = context.getParent();
+          }
+        }
+        TextRange textRange = expression.getTextRange();
+        PsiElement psiExpression = JavaPsiFacade.getInstance(expression.getProject()).getElementFactory().createExpressionFromText(expression.getText(), context);
+        return Pair.create(psiExpression, textRange);
+      }
+      catch (IncorrectOperationException e) {
+        LOG.debug(e);
+      }
+    }
+    return null;
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/MultiProcessCommand.java b/java/debugger/impl/src/com/intellij/debugger/impl/MultiProcessCommand.java
new file mode 100644
index 0000000..db146c9
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/MultiProcessCommand.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl;
+
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.events.DebuggerCommandImpl;
+import com.intellij.openapi.util.Pair;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class MultiProcessCommand implements Runnable{
+  private final List<Pair<DebugProcessImpl,  DebuggerCommandImpl>> myCommands = new ArrayList<Pair<DebugProcessImpl, DebuggerCommandImpl>>();
+
+  public void run() {
+    while(true) {
+      Pair<DebugProcessImpl,  DebuggerCommandImpl> pair;
+      synchronized(myCommands) {
+        if(myCommands.isEmpty()) {
+          break;
+        }
+        pair = myCommands.remove(0);
+      }
+      pair.getFirst().getManagerThread().invokeAndWait(pair.getSecond());
+    }
+  }
+
+  public void cancel() {
+    synchronized(myCommands) {
+      myCommands.clear();
+    }
+  }
+
+  public boolean isEmpty() {
+    return myCommands.isEmpty();
+  }
+
+  public void addCommand(DebugProcessImpl debugProcess, DebuggerCommandImpl command) {
+    myCommands.add(new Pair<DebugProcessImpl, DebuggerCommandImpl>(debugProcess, command));
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/PositionUtil.java b/java/debugger/impl/src/com/intellij/debugger/impl/PositionUtil.java
new file mode 100644
index 0000000..2b23f37
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/PositionUtil.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl;
+
+import com.intellij.debugger.SourcePosition;
+import com.intellij.debugger.engine.ContextUtil;
+import com.intellij.debugger.engine.StackFrameContext;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Computable;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.util.text.CharArrayUtil;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * User: lex
+ * Date: Oct 29, 2003
+ * Time: 9:29:36 PM
+ */
+public class PositionUtil extends ContextUtil {
+  public static SourcePosition getSourcePosition(final StackFrameContext context) {
+    if(context instanceof DebuggerContextImpl) return ((DebuggerContextImpl)context).getSourcePosition();
+
+    return ContextUtil.getSourcePosition(context);
+  }
+
+  public static PsiElement getContextElement(final StackFrameContext context) {
+    if(context instanceof DebuggerContextImpl) return ((DebuggerContextImpl) context).getContextElement();
+
+    return ContextUtil.getContextElement(context);
+  }
+
+  @Nullable
+  public static <T extends PsiElement> T getPsiElementAt(final Project project, final Class<T> expectedPsiElementClass, final SourcePosition sourcePosition) {
+    return ApplicationManager.getApplication().runReadAction(new Computable<T>() {
+      public T compute() {
+        final PsiFile psiFile = sourcePosition.getFile();
+        final Document document = PsiDocumentManager.getInstance(project).getDocument(psiFile);
+        if(document == null) {
+          return null;
+        }
+        final int spOffset = sourcePosition.getOffset();
+        if (spOffset < 0) {
+          return null;
+        }
+        final int offset = CharArrayUtil.shiftForward(document.getCharsSequence(), spOffset, " \t");
+        return PsiTreeUtil.getParentOfType(psiFile.findElementAt(offset), expectedPsiElementClass, false);
+      }
+    });
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/PrioritizedTask.java b/java/debugger/impl/src/com/intellij/debugger/impl/PrioritizedTask.java
new file mode 100644
index 0000000..5848088
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/PrioritizedTask.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: Jul 30, 2009
+ */
+public interface PrioritizedTask {
+  enum Priority {
+    HIGH, NORMAL, LOW
+  }
+
+  Priority getPriority();
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/ReloadClassesWorker.java b/java/debugger/impl/src/com/intellij/debugger/impl/ReloadClassesWorker.java
new file mode 100644
index 0000000..d8d8dd4
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/ReloadClassesWorker.java
@@ -0,0 +1,294 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
+import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
+import com.intellij.debugger.ui.breakpoints.BreakpointManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.progress.ProcessCanceledException;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.util.StringBuilderSpinAllocator;
+import com.intellij.util.ui.MessageCategory;
+import com.intellij.util.ui.UIUtil;
+import com.sun.jdi.ReferenceType;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author lex
+ */
+class ReloadClassesWorker {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.impl.ReloadClassesWorker");
+  private final DebuggerSession  myDebuggerSession;
+  private final HotSwapProgress  myProgress;
+
+  public ReloadClassesWorker(DebuggerSession session, HotSwapProgress progress) {
+    myDebuggerSession = session;
+    myProgress = progress;
+  }
+
+  private DebugProcessImpl getDebugProcess() {
+    return myDebuggerSession.getProcess();
+  }
+
+  private void processException(Throwable e) {
+    if (e.getMessage() != null) {
+      myProgress.addMessage(myDebuggerSession, MessageCategory.ERROR, e.getMessage());
+    }
+
+    if (e instanceof ProcessCanceledException) {
+      myProgress.addMessage(myDebuggerSession, MessageCategory.INFORMATION, DebuggerBundle.message("error.operation.canceled"));
+      return;
+    }
+
+    if (e instanceof UnsupportedOperationException) {
+      myProgress.addMessage(myDebuggerSession, MessageCategory.ERROR, DebuggerBundle.message("error.operation.not.supported.by.vm"));
+    }
+    else if (e instanceof NoClassDefFoundError) {
+      myProgress.addMessage(myDebuggerSession, MessageCategory.ERROR, DebuggerBundle.message("error.class.def.not.found", e.getLocalizedMessage()));
+    }
+    else if (e instanceof VerifyError) {
+      myProgress.addMessage(myDebuggerSession, MessageCategory.ERROR, DebuggerBundle.message("error.verification.error", e.getLocalizedMessage()));
+    }
+    else if (e instanceof UnsupportedClassVersionError) {
+      myProgress.addMessage(myDebuggerSession, MessageCategory.ERROR, DebuggerBundle.message("error.unsupported.class.version", e.getLocalizedMessage()));
+    }
+    else if (e instanceof ClassFormatError) {
+      myProgress.addMessage(myDebuggerSession, MessageCategory.ERROR, DebuggerBundle.message("error.class.format.error", e.getLocalizedMessage()));
+    }
+    else if (e instanceof ClassCircularityError) {
+      myProgress.addMessage(myDebuggerSession, MessageCategory.ERROR, DebuggerBundle.message("error.class.circularity.error", e.getLocalizedMessage()));
+    }
+    else {
+      myProgress.addMessage(
+        myDebuggerSession, MessageCategory.ERROR,
+        DebuggerBundle.message("error.exception.while.reloading", e.getClass().getName(), e.getLocalizedMessage())
+      );
+    }
+  }
+
+  public void reloadClasses(final Map<String, HotSwapFile> modifiedClasses) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+
+    if(modifiedClasses == null || modifiedClasses.size() == 0) {
+      myProgress.addMessage(myDebuggerSession, MessageCategory.INFORMATION, DebuggerBundle.message("status.hotswap.loaded.classes.up.to.date"));
+      return;
+    }
+
+    final DebugProcessImpl debugProcess = getDebugProcess();
+    final VirtualMachineProxyImpl virtualMachineProxy = debugProcess.getVirtualMachineProxy();
+    if(virtualMachineProxy == null) {
+      return;
+    }
+
+    final Project project = debugProcess.getProject();
+    final BreakpointManager breakpointManager = (DebuggerManagerEx.getInstanceEx(project)).getBreakpointManager();
+    breakpointManager.disableBreakpoints(debugProcess);
+
+    //virtualMachineProxy.suspend();
+
+    try {
+      RedefineProcessor redefineProcessor = new RedefineProcessor(virtualMachineProxy);
+
+      int processedClassesCount = 0;
+      for (final String qualifiedName : modifiedClasses.keySet()) {
+        processedClassesCount++;
+        if (qualifiedName != null) {
+          myProgress.setText(qualifiedName);
+          myProgress.setFraction(processedClassesCount / (double)modifiedClasses.size());
+        }
+        final HotSwapFile fileDescr = modifiedClasses.get(qualifiedName);
+        final byte[] content;
+        try {
+          content = FileUtil.loadFileBytes(fileDescr.file);
+        }
+        catch (IOException e) {
+          reportProblem(qualifiedName, e);
+          continue;
+        }
+        redefineProcessor.processClass(qualifiedName, content);
+      }
+      redefineProcessor.processPending();
+      myProgress.setFraction(1);
+
+      final int partiallyRedefinedClassesCount = redefineProcessor.getPartiallyRedefinedClassesCount();
+      if (partiallyRedefinedClassesCount == 0) {
+        myProgress.addMessage(myDebuggerSession, MessageCategory.INFORMATION,
+                              DebuggerBundle.message("status.classes.reloaded", redefineProcessor.getProcessedClassesCount()));
+      }
+      else {
+        final String message = DebuggerBundle.message("status.classes.not.all.versions.reloaded", partiallyRedefinedClassesCount,
+                                                      redefineProcessor.getProcessedClassesCount());
+        myProgress.addMessage(myDebuggerSession, MessageCategory.WARNING, message);
+      }
+
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("classes reloaded");
+      }
+    }
+    catch (Throwable e) {
+      processException(e);
+    }
+
+    //noinspection SSBasedInspection
+    UIUtil.invokeAndWaitIfNeeded(new Runnable() {
+      public void run() {
+        if (project.isDisposed()) {
+          return;
+        }
+        final BreakpointManager breakpointManager = (DebuggerManagerEx.getInstanceEx(project)).getBreakpointManager();
+        breakpointManager.reloadBreakpoints();
+        debugProcess.getRequestsManager().clearWarnings();
+        if (LOG.isDebugEnabled()) {
+          LOG.debug("requests updated");
+          LOG.debug("time stamp set");
+        }
+        myDebuggerSession.refresh(false);
+
+        /*
+        debugProcess.getManagerThread().schedule(new DebuggerCommandImpl() {
+          protected void action() throws Exception {
+            try {
+              breakpointManager.enableBreakpoints(debugProcess);
+            }
+            catch (Exception e) {
+              processException(e);
+            }
+            //try {
+            //  virtualMachineProxy.resume();
+            //}
+            //catch (Exception e) {
+            //  processException(e);
+            //}
+          }
+
+          public Priority getPriority() {
+            return Priority.HIGH;
+          }
+        });
+        */
+      }
+    });
+    try {
+      breakpointManager.enableBreakpoints(debugProcess);
+    }
+    catch (Exception e) {
+      processException(e);
+    }
+  }
+
+  private void reportProblem(final String qualifiedName, @Nullable Exception ex) {
+    String reason = null;
+    if (ex != null)  {
+      reason = ex.getLocalizedMessage();
+    }
+    if (reason == null || reason.length() == 0) {
+      reason = DebuggerBundle.message("error.io.error");
+    }
+    final StringBuilder buf = StringBuilderSpinAllocator.alloc();
+    try {
+      buf.append(qualifiedName).append(" : ").append(reason);
+      myProgress.addMessage(myDebuggerSession, MessageCategory.ERROR, buf.toString());
+    }
+    finally {
+      StringBuilderSpinAllocator.dispose(buf);
+    }
+  }
+
+  private static class RedefineProcessor {
+    /**
+     * number of classes that will be reloaded in one go.
+     * Such restriction is needed to deal with big number of classes being reloaded
+     */
+    private static final int CLASSES_CHUNK_SIZE = 100;
+    private final VirtualMachineProxyImpl myVirtualMachineProxy;
+    private final Map<ReferenceType, byte[]> myRedefineMap = new HashMap<ReferenceType, byte[]>();
+    private int myProcessedClassesCount;
+    private int myPartiallyRedefinedClassesCount;
+
+    public RedefineProcessor(VirtualMachineProxyImpl virtualMachineProxy) {
+      myVirtualMachineProxy = virtualMachineProxy;
+    }
+
+    public void processClass(String qualifiedName, byte[] content) throws Throwable {
+      final List<ReferenceType> vmClasses = myVirtualMachineProxy.classesByName(qualifiedName);
+      if (vmClasses.isEmpty()) return;
+
+      if (vmClasses.size() == 1) {
+        myRedefineMap.put(vmClasses.get(0), content);
+        if (myRedefineMap.size() >= CLASSES_CHUNK_SIZE) {
+          processChunk();
+        }
+        return;
+      }
+
+      int redefinedVersionsCount = 0;
+      Throwable error = null;
+      for (ReferenceType vmClass : vmClasses) {
+        try {
+          myVirtualMachineProxy.redefineClasses(Collections.singletonMap(vmClass, content));
+          redefinedVersionsCount++;
+        }
+        catch (Throwable t) {
+          error = t;
+        }
+      }
+      if (redefinedVersionsCount == 0) {
+        throw error;
+      }
+
+      if (redefinedVersionsCount < vmClasses.size()) {
+        myPartiallyRedefinedClassesCount++;
+      }
+      myProcessedClassesCount++;
+    }
+
+    private void processChunk() throws Throwable {
+      // reload this portion of classes and clear the map to free memory
+      try {
+        myVirtualMachineProxy.redefineClasses(myRedefineMap);
+        myProcessedClassesCount += myRedefineMap.size();
+      }
+      finally {
+        myRedefineMap.clear();
+      }
+    }
+
+    public void processPending() throws Throwable {
+      if (myRedefineMap.size() > 0) {
+        processChunk();
+      }
+    }
+
+    public int getProcessedClassesCount() {
+      return myProcessedClassesCount;
+    }
+
+    public int getPartiallyRedefinedClassesCount() {
+      return myPartiallyRedefinedClassesCount;
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/SimpleStackFrameContext.java b/java/debugger/impl/src/com/intellij/debugger/impl/SimpleStackFrameContext.java
new file mode 100644
index 0000000..207c5be
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/SimpleStackFrameContext.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl;
+
+import com.intellij.debugger.engine.StackFrameContext;
+import com.intellij.debugger.engine.DebugProcess;
+import com.intellij.debugger.engine.jdi.StackFrameProxy;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: Dec 30, 2004
+ */
+public final class SimpleStackFrameContext implements StackFrameContext{
+  private final StackFrameProxy myProxy;
+  private final DebugProcess myProcess;
+
+  public SimpleStackFrameContext(StackFrameProxy proxy, DebugProcess process) {
+    myProxy = proxy;
+    myProcess = process;
+  }
+
+  public StackFrameProxy getFrameProxy() {
+    return myProxy;
+  }
+
+  public DebugProcess getDebugProcess() {
+    return myProcess;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/ArgValueData.java b/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/ArgValueData.java
new file mode 100644
index 0000000..79038ce
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/ArgValueData.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl.descriptors.data;
+
+import com.intellij.debugger.ui.impl.watch.ArgumentValueDescriptorImpl;
+import com.intellij.openapi.project.Project;
+import com.sun.jdi.Value;
+
+public class ArgValueData extends DescriptorData<ArgumentValueDescriptorImpl>{
+  private final int myIndex;
+  private final Value myValue;
+
+  public ArgValueData(int index, Value value) {
+    super();
+    myIndex = index;
+    myValue = value;
+  }
+
+  protected ArgumentValueDescriptorImpl createDescriptorImpl(Project project) {
+    return new ArgumentValueDescriptorImpl(project, myIndex, myValue);
+  }
+
+  public boolean equals(Object object) {
+    if(!(object instanceof ArgValueData)) return false;
+
+    return myIndex == ((ArgValueData)object).myIndex;
+  }
+
+  public int hashCode() {
+    return myIndex;
+  }
+
+  public DisplayKey<ArgumentValueDescriptorImpl> getDisplayKey() {
+    return new SimpleDisplayKey<ArgumentValueDescriptorImpl>(myIndex);
+  }
+}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/ArrayItemData.java b/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/ArrayItemData.java
new file mode 100644
index 0000000..7973da6
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/ArrayItemData.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl.descriptors.data;
+
+import com.intellij.debugger.ui.impl.watch.ArrayElementDescriptorImpl;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.sun.jdi.ArrayReference;
+import org.jetbrains.annotations.NotNull;
+
+public final class ArrayItemData extends DescriptorData<ArrayElementDescriptorImpl>{
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.impl.descriptors.data.ArrayItemData");
+
+  private final ArrayReference myArray;
+  private final int myIndex;
+
+  public ArrayItemData(@NotNull ArrayReference arrRef, int idx) {
+    LOG.assertTrue(0 <= idx);
+    if(LOG.isDebugEnabled()) {
+      LOG.assertTrue(idx <= arrRef.length());
+    }
+    myArray = arrRef;
+    myIndex = idx;
+  }
+
+  protected ArrayElementDescriptorImpl createDescriptorImpl(Project project) {
+    return new ArrayElementDescriptorImpl(project, myArray, myIndex);
+  }
+
+  public DisplayKey<ArrayElementDescriptorImpl> getDisplayKey() {
+    return new ArrayItemDisplayKeyImpl(myIndex);
+  }
+
+  public boolean equals(Object object) {
+    return object instanceof ArrayItemData && myArray.equals(((ArrayItemData)object).myArray) && ((ArrayItemData)object).myIndex == myIndex;
+  }
+
+  public int hashCode() {
+    return myArray.hashCode() + myIndex;
+  }
+
+  private static class ArrayItemDisplayKeyImpl implements DisplayKey<ArrayElementDescriptorImpl> {
+    private final int myIndex;
+
+    public ArrayItemDisplayKeyImpl(int index) {
+      myIndex = index;
+    }
+
+    public boolean equals(Object o) {
+      return o instanceof ArrayItemDisplayKeyImpl && ((ArrayItemDisplayKeyImpl)o).myIndex == myIndex;
+    }
+
+    public int hashCode() {
+      return 0;
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/DescriptorData.java b/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/DescriptorData.java
new file mode 100644
index 0000000..41f9181
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/DescriptorData.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl.descriptors.data;
+
+import com.intellij.debugger.ui.tree.NodeDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Key;
+
+public abstract class DescriptorData <T extends NodeDescriptor> implements DescriptorKey<T>{
+  private static final Key DESCRIPTOR_DATA = new Key("DESCRIPTOR_DATA");
+
+  protected DescriptorData() {
+  }
+
+  public T createDescriptor(Project project) {
+    T descriptor = createDescriptorImpl(project);
+    descriptor.putUserData(DESCRIPTOR_DATA, this);
+    return descriptor;
+  }
+
+  protected abstract T createDescriptorImpl(Project project);
+
+  public abstract boolean equals(Object object);
+
+  public abstract int hashCode();
+
+  public abstract DisplayKey<T> getDisplayKey();
+
+  public static <T extends NodeDescriptor> DescriptorData<T> getDescriptorData(T descriptor) {
+    return (DescriptorData<T>)descriptor.getUserData(DESCRIPTOR_DATA);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/DescriptorKey.java b/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/DescriptorKey.java
new file mode 100644
index 0000000..52fcaec
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/DescriptorKey.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl.descriptors.data;
+
+import com.intellij.debugger.ui.tree.NodeDescriptor;
+
+public interface DescriptorKey <T extends NodeDescriptor>{
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/DisplayKey.java b/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/DisplayKey.java
new file mode 100644
index 0000000..32589f4
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/DisplayKey.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl.descriptors.data;
+
+import com.intellij.debugger.ui.tree.NodeDescriptor;
+
+public interface DisplayKey <T extends NodeDescriptor> extends DescriptorKey<T>{
+  boolean equals(Object object);
+
+  int hashCode();
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/FieldData.java b/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/FieldData.java
new file mode 100644
index 0000000..8392489
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/FieldData.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl.descriptors.data;
+
+import com.intellij.debugger.ui.impl.watch.FieldDescriptorImpl;
+import com.intellij.openapi.project.Project;
+import com.sun.jdi.Field;
+import com.sun.jdi.ObjectReference;
+import org.jetbrains.annotations.NotNull;
+
+public final class FieldData extends DescriptorData<FieldDescriptorImpl>{
+  private final ObjectReference myObjRef;
+  private final Field myField;
+
+  public FieldData(@NotNull ObjectReference objRef, @NotNull Field field) {
+    myObjRef = objRef;
+    myField = field;
+  }
+
+  protected FieldDescriptorImpl createDescriptorImpl(Project project) {
+    return new FieldDescriptorImpl(project, myObjRef, myField);
+  }
+
+  public boolean equals(Object object) {
+    if(!(object instanceof FieldData)) {
+      return false;
+    }
+    final FieldData fieldData = (FieldData)object;
+    return fieldData.myField == myField && fieldData.myObjRef.equals(myObjRef);
+  }
+
+  public int hashCode() {
+    return myObjRef.hashCode() + myField.hashCode();
+  }
+
+  public DisplayKey<FieldDescriptorImpl> getDisplayKey() {
+    return new SimpleDisplayKey<FieldDescriptorImpl>(myField);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/LocalData.java b/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/LocalData.java
new file mode 100644
index 0000000..3e401a0
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/LocalData.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl.descriptors.data;
+
+import com.intellij.debugger.jdi.LocalVariableProxyImpl;
+import com.intellij.debugger.ui.impl.watch.LocalVariableDescriptorImpl;
+import com.intellij.openapi.project.Project;
+import com.intellij.util.StringBuilderSpinAllocator;
+
+public class LocalData extends DescriptorData<LocalVariableDescriptorImpl>{
+  private final LocalVariableProxyImpl myLocalVariable;
+
+  public LocalData(LocalVariableProxyImpl localVariable) {
+    super();
+    myLocalVariable = localVariable;
+  }
+
+  protected LocalVariableDescriptorImpl createDescriptorImpl(Project project) {
+    return new LocalVariableDescriptorImpl(project, myLocalVariable);
+  }
+
+  public boolean equals(Object object) {
+    if(!(object instanceof LocalData)) return false;
+
+    return ((LocalData)object).myLocalVariable.equals(myLocalVariable);
+  }
+
+  public int hashCode() {
+    return myLocalVariable.hashCode();
+  }
+
+  public DisplayKey<LocalVariableDescriptorImpl> getDisplayKey() {
+    final StringBuilder builder = StringBuilderSpinAllocator.alloc();
+    try {
+      return new SimpleDisplayKey<LocalVariableDescriptorImpl>(builder.append(myLocalVariable.typeName()).append("#").append(myLocalVariable.name()).toString());
+    }
+    finally {
+      StringBuilderSpinAllocator.dispose(builder);
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/MethodReturnValueData.java b/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/MethodReturnValueData.java
new file mode 100644
index 0000000..1139b2f
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/MethodReturnValueData.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl.descriptors.data;
+
+import com.intellij.debugger.ui.impl.watch.MethodReturnValueDescriptorImpl;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Pair;
+import com.sun.jdi.Method;
+import com.sun.jdi.Value;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public final class MethodReturnValueData extends DescriptorData<MethodReturnValueDescriptorImpl>{
+  private final @Nullable Value myReturnValue;
+  private final @NotNull Method myMethod;
+
+  public MethodReturnValueData(@NotNull Method method, @Nullable Value returnValue) {
+    super();
+    myMethod = method;
+    myReturnValue = returnValue;
+  }
+
+  public @Nullable Value getReturnValue() {
+    return myReturnValue;
+  }
+
+  public @NotNull Method getMethod() {
+    return myMethod;
+  }
+
+  protected MethodReturnValueDescriptorImpl createDescriptorImpl(Project project) {
+    return new MethodReturnValueDescriptorImpl(project, myMethod, myReturnValue);
+  }
+
+
+  public boolean equals(final Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    final MethodReturnValueData that = (MethodReturnValueData)o;
+
+    if (!myMethod.equals(that.myMethod)) return false;
+    if (myReturnValue != null ? !myReturnValue.equals(that.myReturnValue) : that.myReturnValue != null) return false;
+
+    return true;
+  }
+
+  public int hashCode() {
+    int result;
+    result = (myReturnValue != null ? myReturnValue.hashCode() : 0);
+    result = 31 * result + myMethod.hashCode();
+    return result;
+  }
+
+  public DisplayKey<MethodReturnValueDescriptorImpl> getDisplayKey() {
+    return new MethodReturnValueDisplayKey(myMethod, myReturnValue);
+  }
+
+  private static final class MethodReturnValueDisplayKey extends Pair<Method, Value> implements DisplayKey<MethodReturnValueDescriptorImpl> {
+    public MethodReturnValueDisplayKey(@NotNull Method method, @Nullable Value value) {
+      super(method, value);
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/SimpleDisplayKey.java b/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/SimpleDisplayKey.java
new file mode 100644
index 0000000..3762611
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/SimpleDisplayKey.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl.descriptors.data;
+
+import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl;
+import com.intellij.debugger.ui.tree.NodeDescriptor;
+
+public class SimpleDisplayKey<T extends NodeDescriptor> implements DisplayKey<T>{
+  private final Object myKey;
+
+  public SimpleDisplayKey(Object key) {
+    myKey = key;
+  }
+
+  public boolean equals(Object o) {
+    if(!(o instanceof SimpleDisplayKey)) return false;
+    return ((SimpleDisplayKey)o).myKey.equals(myKey);
+  }
+
+  public int hashCode() {
+    return myKey.hashCode();
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/StackFrameData.java b/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/StackFrameData.java
new file mode 100644
index 0000000..6dc8400
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/StackFrameData.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl.descriptors.data;
+
+import com.intellij.debugger.jdi.StackFrameProxyImpl;
+import com.intellij.debugger.ui.impl.watch.MethodsTracker;
+import com.intellij.debugger.ui.impl.watch.NodeManagerImpl;
+import com.intellij.debugger.ui.impl.watch.StackFrameDescriptorImpl;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Comparing;
+
+public class StackFrameData extends DescriptorData<StackFrameDescriptorImpl>{
+  private final StackFrameProxyImpl myFrame;
+  private final FrameDisplayKey myDisplayKey;
+  private final MethodsTracker myMethodsTracker;
+
+  public StackFrameData(StackFrameProxyImpl frame) {
+    super();
+    myFrame = frame;
+    myDisplayKey = new FrameDisplayKey(NodeManagerImpl.getContextKeyForFrame(frame));
+    myMethodsTracker = new MethodsTracker();
+    
+  }
+
+  protected StackFrameDescriptorImpl createDescriptorImpl(Project project) {
+    return new StackFrameDescriptorImpl(myFrame, myMethodsTracker);
+  }
+
+  public boolean equals(Object object) {
+    if(!(object instanceof StackFrameData)) return false;
+
+    return ((StackFrameData)object).myFrame == myFrame;
+  }
+
+  public int hashCode() {
+    return myFrame.hashCode();
+  }
+
+  public DisplayKey<StackFrameDescriptorImpl> getDisplayKey() {
+    return myDisplayKey;
+  }
+
+  private static class FrameDisplayKey implements DisplayKey<StackFrameDescriptorImpl>{
+    private final String myContextKey;
+
+    public FrameDisplayKey(final String contextKey) {
+      myContextKey = contextKey;
+    }
+
+    public boolean equals(final Object o) {
+      if (this == o) return true;
+      if (o == null || getClass() != o.getClass()) return false;
+
+      final FrameDisplayKey that = (FrameDisplayKey)o;
+
+      if (!Comparing.equal(myContextKey, that.myContextKey)) return false;
+      
+      return true;
+    }
+
+    public int hashCode() {
+      return myContextKey == null? 0 : myContextKey.hashCode();
+    }
+  } 
+  
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/StaticData.java b/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/StaticData.java
new file mode 100644
index 0000000..178954b
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/StaticData.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl.descriptors.data;
+
+import com.intellij.debugger.ui.impl.watch.StaticDescriptorImpl;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Key;
+import com.sun.jdi.ReferenceType;
+import org.jetbrains.annotations.NotNull;
+
+public final class StaticData extends DescriptorData<StaticDescriptorImpl>{
+  private static final Key STATIC = new Key("STATIC");
+
+  private final ReferenceType myRefType;
+
+  public StaticData(@NotNull ReferenceType refType) {
+    myRefType = refType;
+  }
+
+  public ReferenceType getRefType() {
+    return myRefType;
+  }
+
+  protected StaticDescriptorImpl createDescriptorImpl(Project project) {
+    return new StaticDescriptorImpl(myRefType);
+  }
+
+  public boolean equals(Object object) {
+    return object instanceof StaticData;
+
+  }
+
+  public int hashCode() {
+    return STATIC.hashCode();
+  }
+
+  public DisplayKey<StaticDescriptorImpl> getDisplayKey() {
+    return new SimpleDisplayKey<StaticDescriptorImpl>(STATIC);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/StaticFieldData.java b/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/StaticFieldData.java
new file mode 100644
index 0000000..adfbd3a
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/StaticFieldData.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl.descriptors.data;
+
+import com.intellij.debugger.ui.impl.watch.FieldDescriptorImpl;
+import com.intellij.openapi.project.Project;
+import com.sun.jdi.Field;
+import org.jetbrains.annotations.NotNull;
+
+public final class StaticFieldData extends DescriptorData<FieldDescriptorImpl>{
+  private final Field myField;
+
+  public StaticFieldData(@NotNull Field field) {
+    myField = field;
+  }
+
+  protected FieldDescriptorImpl createDescriptorImpl(Project project) {
+    return new FieldDescriptorImpl(project, null, myField);
+  }
+
+  public boolean equals(Object object) {
+    if(!(object instanceof StaticFieldData)) {
+      return false;
+    }
+    final StaticFieldData fieldData = (StaticFieldData)object;
+    return (fieldData.myField == myField);
+  }
+
+  public int hashCode() {
+    return myField.hashCode();
+  }
+
+  public DisplayKey<FieldDescriptorImpl> getDisplayKey() {
+    return new SimpleDisplayKey<FieldDescriptorImpl>(myField);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/ThisData.java b/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/ThisData.java
new file mode 100644
index 0000000..9a7afd6
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/ThisData.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl.descriptors.data;
+
+import com.intellij.debugger.ui.impl.watch.ThisDescriptorImpl;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Key;
+
+public final class ThisData extends DescriptorData<ThisDescriptorImpl>{
+
+  private static final Key THIS = new Key("THIS");
+
+  protected ThisDescriptorImpl createDescriptorImpl(Project project) {
+    return new ThisDescriptorImpl(project);
+  }
+
+  public boolean equals(Object object) {
+    if(!(object instanceof ThisData)) return false;
+
+    return true;
+  }
+
+  public int hashCode() {
+    return THIS.hashCode();
+  }
+
+  public DisplayKey<ThisDescriptorImpl> getDisplayKey() {
+    return new SimpleDisplayKey<ThisDescriptorImpl>(THIS);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/ThreadData.java b/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/ThreadData.java
new file mode 100644
index 0000000..543ce53
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/ThreadData.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl.descriptors.data;
+
+import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
+import com.intellij.debugger.ui.impl.watch.ThreadDescriptorImpl;
+import com.intellij.openapi.project.Project;
+
+public class ThreadData extends DescriptorData<ThreadDescriptorImpl> {
+  private final ThreadReferenceProxyImpl myThread;
+  public ThreadData(ThreadReferenceProxyImpl thread) {
+    super();
+    myThread = thread;
+  }
+
+  protected ThreadDescriptorImpl createDescriptorImpl(Project project) {
+    return new ThreadDescriptorImpl(myThread);
+  }
+
+  public boolean equals(Object object) {
+    if(!(object instanceof ThreadData)) {
+      return false;
+    }
+    return myThread.equals(((ThreadData)object).myThread);
+  }
+
+  public int hashCode() {
+    return myThread.hashCode();
+  }
+
+  public DisplayKey<ThreadDescriptorImpl> getDisplayKey() {
+    return new SimpleDisplayKey<ThreadDescriptorImpl>(myThread);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/ThreadGroupData.java b/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/ThreadGroupData.java
new file mode 100644
index 0000000..fef9333
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/ThreadGroupData.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl.descriptors.data;
+
+import com.intellij.debugger.jdi.ThreadGroupReferenceProxyImpl;
+import com.intellij.debugger.ui.impl.watch.ThreadGroupDescriptorImpl;
+import com.intellij.openapi.project.Project;
+
+public class ThreadGroupData extends DescriptorData<ThreadGroupDescriptorImpl>{
+  private final ThreadGroupReferenceProxyImpl myThreadGroup;
+
+  public ThreadGroupData(ThreadGroupReferenceProxyImpl threadGroup) {
+    super();
+    myThreadGroup = threadGroup;
+  }
+
+  protected ThreadGroupDescriptorImpl createDescriptorImpl(Project project) {
+    return new ThreadGroupDescriptorImpl(myThreadGroup);
+  }
+
+  public boolean equals(Object object) {
+    if(!(object instanceof ThreadGroupData)) return false;
+
+    return myThreadGroup.equals(((ThreadGroupData)object).myThreadGroup);
+  }
+
+  public int hashCode() {
+    return myThreadGroup.hashCode();
+  }
+
+  public DisplayKey<ThreadGroupDescriptorImpl> getDisplayKey() {
+    return new SimpleDisplayKey<ThreadGroupDescriptorImpl>(myThreadGroup);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/UserExpressionData.java b/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/UserExpressionData.java
new file mode 100644
index 0000000..5553d3b
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/UserExpressionData.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl.descriptors.data;
+
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.debugger.ui.impl.watch.UserExpressionDescriptorImpl;
+import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl;
+import com.intellij.debugger.ui.tree.UserExpressionDescriptor;
+import com.intellij.openapi.project.Project;
+
+public class UserExpressionData extends DescriptorData<UserExpressionDescriptor>{
+  private final ValueDescriptorImpl myParentDescriptor;
+  private final String myTypeName;
+  private final String myName;
+  protected TextWithImports myText;
+
+  public UserExpressionData(ValueDescriptorImpl parentDescriptor, String typeName, String name, TextWithImports text) {
+    super();
+    myParentDescriptor = parentDescriptor;
+    myTypeName = typeName;
+    myName = name;
+    myText = text;
+  }
+
+  protected UserExpressionDescriptorImpl createDescriptorImpl(Project project) {
+    return new UserExpressionDescriptorImpl(project, myParentDescriptor, myTypeName, myName, myText);
+  }
+
+  public boolean equals(Object object) {
+    if(!(object instanceof UserExpressionData)) return false;
+
+    return myName.equals(((UserExpressionData)object).myName);
+  }
+
+  public int hashCode() {
+    return myName.hashCode();
+  }
+
+  public DisplayKey<UserExpressionDescriptor> getDisplayKey() {
+    return new SimpleDisplayKey<UserExpressionDescriptor>(myTypeName + myName);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/WatchItemData.java b/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/WatchItemData.java
new file mode 100644
index 0000000..4b44a0d
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/descriptors/data/WatchItemData.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2000-2009 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.debugger.impl.descriptors.data;
+
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.debugger.ui.impl.watch.WatchItemDescriptor;
+import com.intellij.openapi.project.Project;
+import com.sun.jdi.Value;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: May 30, 2007
+ */
+public final class WatchItemData extends DescriptorData<WatchItemDescriptor>{
+  private final TextWithImports myText;
+  private final Value myValue;
+
+  public WatchItemData(TextWithImports text, @Nullable Value value) {
+    myText = text;
+    myValue = value;
+  }
+
+  protected WatchItemDescriptor createDescriptorImpl(final Project project) {
+    return new WatchItemDescriptor(project, myText, myValue);
+  }
+
+  public boolean equals(final Object object) {
+    if (object instanceof WatchItemData) {
+      return myText.equals(((WatchItemData)object).myText);
+    }
+    return false;
+  }
+
+  public int hashCode() {
+    return myText.hashCode();
+  }
+
+  public DisplayKey<WatchItemDescriptor> getDisplayKey() {
+    return new SimpleDisplayKey<WatchItemDescriptor>(myText.getText());
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/jdi/JdiProxy.java b/java/debugger/impl/src/com/intellij/debugger/jdi/JdiProxy.java
new file mode 100644
index 0000000..ab8a3ce
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/jdi/JdiProxy.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2000-2009 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.debugger.jdi;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: lex
+ * Date: Jul 10, 2003
+ * Time: 4:53:44 PM
+ * To change this template use Options | File Templates.
+ */
+public abstract class JdiProxy {
+  protected JdiTimer myTimer;
+  private int myTimeStamp = 0;
+
+  public JdiProxy(JdiTimer timer) {
+    myTimer = timer;
+    myTimeStamp = myTimer.getCurrentTime();
+  }
+
+  protected void checkValid() {
+    if(!isValid()) {
+      myTimeStamp = myTimer.getCurrentTime();
+      clearCaches();
+    }
+  }
+
+  /**
+   * @deprecated for testing only
+   * @return
+   */
+  public boolean isValid() {
+    return myTimeStamp == myTimer.getCurrentTime();
+  }
+
+  protected abstract void clearCaches();
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/jdi/JdiTimer.java b/java/debugger/impl/src/com/intellij/debugger/jdi/JdiTimer.java
new file mode 100644
index 0000000..2bef610
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/jdi/JdiTimer.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2000-2009 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.debugger.jdi;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: lex
+ * Date: Jul 10, 2003
+ * Time: 5:13:25 PM
+ * To change this template use Options | File Templates.
+ */
+interface JdiTimer {
+  int getCurrentTime();
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/jdi/LocalVariableProxyImpl.java b/java/debugger/impl/src/com/intellij/debugger/jdi/LocalVariableProxyImpl.java
new file mode 100644
index 0000000..0ccda00
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/jdi/LocalVariableProxyImpl.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2000-2009 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.debugger.jdi;
+
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.engine.jdi.LocalVariableProxy;
+import com.intellij.openapi.util.Comparing;
+import com.sun.jdi.ClassNotLoadedException;
+import com.sun.jdi.IncompatibleThreadStateException;
+import com.sun.jdi.LocalVariable;
+import com.sun.jdi.Type;
+
+public class LocalVariableProxyImpl extends JdiProxy implements LocalVariableProxy {
+  private final StackFrameProxyImpl myFrame;
+  private final String myVariableName;
+  private final String myTypeName;
+
+  private LocalVariable myVariable;
+  private Type myVariableType;
+
+  public LocalVariableProxyImpl(StackFrameProxyImpl frame, LocalVariable variable) {
+    super(frame.myTimer);
+    myFrame = frame;
+    myVariableName = variable.name();
+    myTypeName = variable.typeName();
+    myVariable = variable;
+  }
+
+  protected void clearCaches() {
+    myVariable = null;
+    myVariableType = null;
+  }
+
+  public LocalVariable getVariable() throws EvaluateException {
+    checkValid();
+    if(myVariable == null) {
+      myVariable = myFrame.visibleVariableByNameInt(myVariableName);
+
+      if(myVariable == null) {
+        //myFrame is not this variable's frame
+        throw EvaluateExceptionUtil.createEvaluateException(new IncompatibleThreadStateException());
+      }
+    }
+
+    return myVariable;
+  }
+
+  public Type getType() throws EvaluateException, ClassNotLoadedException {
+    if (myVariableType == null) {
+      myVariableType = getVariable().type();
+    }
+    return myVariableType;
+  }
+  
+  public StackFrameProxyImpl getFrame() {
+    return myFrame;
+  }
+
+  public int hashCode() {
+    return 31 * myFrame.hashCode() + myVariableName.hashCode();
+  }
+
+  public boolean equals(Object o) {
+    if(o instanceof LocalVariableProxyImpl) {
+      LocalVariableProxyImpl proxy = (LocalVariableProxyImpl)o;
+      return Comparing.equal(proxy.myFrame, myFrame) && myVariableName.equals(proxy.myVariableName);
+    }
+    return false;
+  }
+
+  public String name() {
+    return myVariableName;
+  }
+
+  public String typeName() {
+    return myTypeName;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/jdi/ObjectReferenceProxyImpl.java b/java/debugger/impl/src/com/intellij/debugger/jdi/ObjectReferenceProxyImpl.java
new file mode 100644
index 0000000..4e39599
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/jdi/ObjectReferenceProxyImpl.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * @author Eugene Zhuravlev
+ */
+package com.intellij.debugger.jdi;
+
+import com.sun.jdi.*;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class ObjectReferenceProxyImpl extends JdiProxy {
+  private final ObjectReference myObjectReference;
+
+  //caches
+  private ReferenceType myReferenceType;
+  private Type myType;
+  private Boolean myIsCollected = null;
+
+  public ObjectReferenceProxyImpl(VirtualMachineProxyImpl virtualMachineProxy, @NotNull ObjectReference objectReference) {
+    super(virtualMachineProxy);
+    myObjectReference = objectReference;
+  }
+
+  public ObjectReference getObjectReference() {
+    checkValid();
+    return myObjectReference;
+  }
+
+  public VirtualMachineProxyImpl getVirtualMachineProxy() {
+    return (VirtualMachineProxyImpl) myTimer;
+  }
+
+  public ReferenceType referenceType() {
+    checkValid();
+    if (myReferenceType == null) {
+      myReferenceType = getObjectReference().referenceType();
+    }
+    return myReferenceType;
+  }
+
+  public Type type() {
+    checkValid();
+    if (myType == null) {
+      myType = getObjectReference().type();
+    }
+    return myType;
+  }
+
+  @NonNls
+  public String toString() {
+    final ObjectReference objectReference = getObjectReference();
+    //noinspection HardCodedStringLiteral
+    final String objRefString = objectReference != null? objectReference.toString() : "[referenced object collected]";
+    return "ObjectReferenceProxyImpl: " + objRefString + " " + super.toString();
+  }
+
+  public Map<Field, Value> getValues(List<? extends Field> list) {
+    return getObjectReference().getValues(list);
+  }
+
+  public void setValue(Field field, Value value) throws InvalidTypeException, ClassNotLoadedException {
+    getObjectReference().setValue(field, value);
+  }
+
+  public boolean isCollected() {
+    checkValid();
+    if (myIsCollected == null || Boolean.FALSE.equals(myIsCollected)) {
+      try {
+        myIsCollected = Boolean.valueOf(VirtualMachineProxyImpl.isCollected(myObjectReference));
+      }
+      catch (VMDisconnectedException e) {
+        myIsCollected = Boolean.TRUE;
+      }
+    }
+    return myIsCollected.booleanValue();
+  }
+
+  public long uniqueID() {
+    return getObjectReference().uniqueID();
+  }
+
+  /**
+   * @return a list of waiting ThreadReferenceProxies
+   * @throws IncompatibleThreadStateException
+   */
+  public List<ThreadReferenceProxyImpl> waitingThreads() throws IncompatibleThreadStateException {
+    List<ThreadReference> list = getObjectReference().waitingThreads();
+    List<ThreadReferenceProxyImpl> proxiesList = new ArrayList<ThreadReferenceProxyImpl>(list.size());
+
+    for (ThreadReference threadReference : list) {
+      proxiesList.add(getVirtualMachineProxy().getThreadReferenceProxy(threadReference));
+    }
+    return proxiesList;
+  }
+
+  public ThreadReferenceProxyImpl owningThread() throws IncompatibleThreadStateException {
+    ThreadReference threadReference = getObjectReference().owningThread();
+    return getVirtualMachineProxy().getThreadReferenceProxy(threadReference);
+  }
+
+  public int entryCount() throws IncompatibleThreadStateException {
+    return getObjectReference().entryCount();
+  }
+
+  public boolean equals(Object o) {
+    if (!(o instanceof ObjectReferenceProxyImpl)) {
+      return false;
+    }
+    if(this == o) return true;
+
+    ObjectReference ref = myObjectReference;
+    return ref != null && ref.equals(((ObjectReferenceProxyImpl)o).myObjectReference);
+  }
+
+
+  public int hashCode() {
+    return myObjectReference.hashCode();
+  }
+
+  /**
+   * The advice to the proxy to clear cached data.
+   */
+  protected void clearCaches() {
+    if (Boolean.FALSE.equals(myIsCollected)) {
+      // clearing cache makes sence only if the object has not been collected yet
+      myIsCollected = null;
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/jdi/StackFrameProxyImpl.java b/java/debugger/impl/src/com/intellij/debugger/jdi/StackFrameProxyImpl.java
new file mode 100644
index 0000000..01a6c14
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/jdi/StackFrameProxyImpl.java
@@ -0,0 +1,366 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * @author Eugene Zhuravlev
+ */
+package com.intellij.debugger.jdi;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.engine.jdi.StackFrameProxy;
+import com.intellij.openapi.diagnostic.Logger;
+import com.sun.jdi.*;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.*;
+
+public class StackFrameProxyImpl extends JdiProxy implements StackFrameProxy {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.jdi.StackFrameProxyImpl");
+  private final ThreadReferenceProxyImpl myThreadProxy;
+  private final int myFrameFromBottomIndex; // 1-based
+
+  //caches
+  private int myFrameIndex = -1;
+  private StackFrame myStackFrame;
+  private ObjectReference myThisReference;
+  private ClassLoaderReference myClassLoader;
+  private Boolean myIsObsolete = null;
+  private Map<LocalVariable,Value> myAllValues;
+
+  public StackFrameProxyImpl(ThreadReferenceProxyImpl threadProxy, @NotNull StackFrame frame, int fromBottomIndex /* 1-based */) {
+    super(threadProxy.getVirtualMachine());
+    myThreadProxy = threadProxy;
+    myFrameFromBottomIndex = fromBottomIndex;
+    myStackFrame = frame;
+  }
+
+  public boolean isObsolete() throws EvaluateException {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    checkValid();
+    if (myIsObsolete == null) {
+      try {
+        boolean isObsolete = (getVirtualMachine().canRedefineClasses() && location().method().isObsolete());
+        //boolean isObsolete = (getVirtualMachine().versionHigher("1.4") && location().method().isObsolete());
+        myIsObsolete = isObsolete? Boolean.TRUE : Boolean.FALSE;
+      }
+      catch (InvalidStackFrameException e) {
+        clearCaches();
+        return isObsolete();
+      }
+      catch (InternalException e) {
+        if (e.errorCode() == 23 /*INVALID_METHODID accoeding to JDI sources*/) {
+          myIsObsolete = Boolean.TRUE;
+        }
+        else {
+          throw e;
+        }
+      }
+    }
+    return myIsObsolete.booleanValue();
+  }
+
+  protected void clearCaches() {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    //DebuggerManagerThreadImpl.assertIsManagerThread();
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("caches cleared " + super.toString());
+    }
+    myFrameIndex = -1;
+    myStackFrame = null;
+    myIsObsolete = null;
+    myThisReference = null;
+    myClassLoader = null;
+    myAllValues = null;
+  }
+
+  /**
+   * Use with caution. Better access stackframe data through the Proxy's methods
+   */
+
+  public StackFrame getStackFrame() throws EvaluateException  {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+
+    checkValid();
+
+    if(myStackFrame == null) {
+      try {
+        final ThreadReference threadRef = myThreadProxy.getThreadReference();
+        myStackFrame = threadRef.frame(getFrameIndex());
+      }
+      catch (IndexOutOfBoundsException e) {
+        throw new EvaluateException(e.getMessage(), e);
+      }
+      catch (ObjectCollectedException e) {
+        throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.thread.collected"));
+      }
+      catch (IncompatibleThreadStateException e) {
+        throw EvaluateExceptionUtil.createEvaluateException(e);
+      }
+    }
+
+    return myStackFrame;
+  }
+
+  public int getFrameIndex() throws EvaluateException {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    checkValid();
+    if(myFrameIndex == -1) {
+      int count = myThreadProxy.frameCount();
+
+      if(myFrameFromBottomIndex  > count) {
+        throw EvaluateExceptionUtil.createEvaluateException(new IncompatibleThreadStateException());
+      }
+
+      myFrameIndex = count - myFrameFromBottomIndex;
+    }
+    return myFrameIndex;
+  }
+
+//  public boolean isProxiedFrameValid() {
+//    if (myStackFrame != null) {
+//      try {
+//        myStackFrame.thread();
+//        return true;
+//      }
+//      catch (InvalidStackFrameException e) {
+//      }
+//    }
+//    return false;
+//  }
+
+  public VirtualMachineProxyImpl getVirtualMachine() {
+    return (VirtualMachineProxyImpl) myTimer;
+  }
+
+  public Location location() throws EvaluateException {
+    try {
+      return getStackFrame().location();
+    }
+    catch (InvalidStackFrameException e) {
+      clearCaches();
+      return location();
+    }
+  }
+
+  public ThreadReferenceProxyImpl threadProxy() {
+    return myThreadProxy;
+  }
+
+  public @NonNls String toString() {
+    try {
+      return "StackFrameProxyImpl: " + getStackFrame().toString();
+    }
+    catch (EvaluateException e) {
+      return "StackFrameProxyImpl: " + e.getMessage() + "; frameFromBottom = " + myFrameFromBottomIndex + " threadName = " + threadProxy().name();
+    }
+  }
+
+  public ObjectReference thisObject() throws EvaluateException {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    checkValid();
+    try {
+      if(myThisReference == null) {
+        myThisReference = getStackFrame().thisObject();
+      }
+    }
+    catch (InvalidStackFrameException e) {
+      clearCaches();
+      return thisObject();
+    }
+    catch (InternalException e) {
+      // supress some internal errors caused by bugs in specific JDI implementations
+      if(e.errorCode() != 23) {
+        throw EvaluateExceptionUtil.createEvaluateException(e);
+      }
+    }
+    return myThisReference;
+  }
+
+  public List<LocalVariableProxyImpl> visibleVariables() throws EvaluateException {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    try {
+      List<LocalVariable> list = getStackFrame().visibleVariables();
+
+      List<LocalVariableProxyImpl> locals = new ArrayList<LocalVariableProxyImpl>();
+      for (Iterator<LocalVariable> iterator = list.iterator(); iterator.hasNext();) {
+        LocalVariable localVariable = iterator.next();
+        LOG.assertTrue(localVariable != null);
+        locals.add(new LocalVariableProxyImpl(this, localVariable));
+      }
+      return locals;
+    }
+    catch (InvalidStackFrameException e) {
+      clearCaches();
+      return visibleVariables();
+    }
+    catch (AbsentInformationException e) {
+      throw EvaluateExceptionUtil.createEvaluateException(e);
+    }
+  }
+
+  public LocalVariableProxyImpl visibleVariableByName(String name) throws EvaluateException  {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    final LocalVariable variable = visibleVariableByNameInt(name);
+    return variable != null ? new LocalVariableProxyImpl(this, variable) : null;
+  }
+
+  protected LocalVariable visibleVariableByNameInt(String name) throws EvaluateException  {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    try {
+      try {
+        return getStackFrame().visibleVariableByName(name);
+      }
+      catch (InvalidStackFrameException e) {
+        clearCaches();
+        return getStackFrame().visibleVariableByName(name);
+      }
+    }
+    catch (InvalidStackFrameException e) {
+      throw EvaluateExceptionUtil.createEvaluateException(e);
+    }
+    catch (AbsentInformationException e) {
+      throw EvaluateExceptionUtil.createEvaluateException(e);
+    }
+  }
+
+  public Value getValue(LocalVariableProxyImpl localVariable) throws EvaluateException {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    try {
+      final Map<LocalVariable, Value> allValues = getAllValues();
+      return allValues.get(localVariable.getVariable());
+    }
+    catch (InvalidStackFrameException e) {
+      clearCaches();
+      return getValue(localVariable);
+    }
+  }
+
+  public List<Value> getArgumentValues() throws EvaluateException {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    try {
+      final StackFrame stackFrame = getStackFrame();
+      if (stackFrame != null) {
+        return stackFrame.getArgumentValues();
+      }
+      return Collections.emptyList();
+    }
+    catch (InternalException e) {
+      // From Oracle's forums:
+      // This could be a JPDA bug. Unexpected JDWP Error: 32 means that an 'opaque' frame was detected at the lower JPDA levels,
+      // typically a native frame.
+      if (e.errorCode() == 32 /*opaque frame JDI bug*/ ) {
+        return Collections.emptyList();
+      }
+      else {
+        throw e;
+      }
+    }
+    catch (InvalidStackFrameException e) {
+      clearCaches();
+      return getArgumentValues();
+    }
+  }
+
+  private Map<LocalVariable, Value> getAllValues() throws EvaluateException{
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    checkValid();
+    if (myAllValues == null) {
+      try {
+        final StackFrame stackFrame = getStackFrame();
+        final Map<LocalVariable, Value> values = stackFrame.getValues(stackFrame.visibleVariables());
+        myAllValues = new HashMap<LocalVariable, Value>(values.size());
+        for (final LocalVariable variable : values.keySet()) {
+          final Value value = values.get(variable);
+          myAllValues.put(variable, value);
+        }
+      }
+      catch (InconsistentDebugInfoException e) {
+        clearCaches();
+        throw EvaluateExceptionUtil.INCONSISTEND_DEBUG_INFO;
+      }
+      catch (AbsentInformationException e) {
+        throw EvaluateExceptionUtil.createEvaluateException(e);
+      }
+    }
+    return myAllValues;
+  }
+
+  public void setValue(LocalVariableProxyImpl localVariable, Value value) throws EvaluateException,
+                                                                                 ClassNotLoadedException,
+                                                                                 InvalidTypeException {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    try {
+      final LocalVariable variable = localVariable.getVariable();
+      final StackFrame stackFrame = getStackFrame();
+      stackFrame.setValue(variable, (value instanceof ObjectReference)? ((ObjectReference)value) : value);
+      if (myAllValues != null) {
+        // update cached data if any
+        // re-read the value just set from the stackframe to be 100% sure
+        myAllValues.put(variable, stackFrame.getValue(variable));
+      }
+    }
+    catch (InvalidStackFrameException e) {
+      clearCaches();
+      setValue(localVariable, value);
+    }
+  }
+
+  public int hashCode() {
+    return 31 * myThreadProxy.hashCode() + myFrameFromBottomIndex;
+  }
+
+
+  public boolean equals(final Object obj) {
+    if (!(obj instanceof StackFrameProxyImpl)) {
+      return false;
+    }
+    StackFrameProxyImpl frameProxy = (StackFrameProxyImpl)obj;
+    if(frameProxy == this)return true;
+
+    return (myFrameFromBottomIndex == frameProxy.myFrameFromBottomIndex)  &&
+           (myThreadProxy.equals(frameProxy.myThreadProxy));
+  }
+
+  public boolean isLocalVariableVisible(LocalVariableProxyImpl var) throws EvaluateException {
+    try {
+      return var.getVariable().isVisible(getStackFrame());
+    }
+    catch (IllegalArgumentException e) {
+      // can be thrown if frame's method is different than variable's method
+      return false;
+    }
+  }
+
+  public ClassLoaderReference getClassLoader() throws EvaluateException {
+    if(myClassLoader == null) {
+      myClassLoader = location().declaringType().classLoader();
+    }
+    return myClassLoader;
+  }
+
+  public boolean isBottom() {
+    return myFrameFromBottomIndex == 1;
+  }
+
+  public int getIndexFromBottom() {
+    return myFrameFromBottomIndex;
+  }
+}
+
diff --git a/java/debugger/impl/src/com/intellij/debugger/jdi/StringReferenceProxy.java b/java/debugger/impl/src/com/intellij/debugger/jdi/StringReferenceProxy.java
new file mode 100644
index 0000000..01aa8e5
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/jdi/StringReferenceProxy.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * @author Eugene Zhuravlev
+ */
+package com.intellij.debugger.jdi;
+
+import com.sun.jdi.StringReference;
+
+public class StringReferenceProxy extends ObjectReferenceProxyImpl{
+  private String myStringValue;
+
+  public StringReferenceProxy(VirtualMachineProxyImpl virtualMachineProxy, StringReference objectReference) {
+    super(virtualMachineProxy, objectReference);
+  }
+
+  public StringReference getStringReference() {
+    return (StringReference)getObjectReference();
+  }
+
+  public String value() {
+    checkValid();
+    if (myStringValue == null) {
+      myStringValue = getStringReference().value();
+    }
+    return myStringValue;
+  }
+
+  public void clearCaches() {
+    myStringValue = null;
+    super.clearCaches();
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/jdi/ThreadGroupReferenceProxyImpl.java b/java/debugger/impl/src/com/intellij/debugger/jdi/ThreadGroupReferenceProxyImpl.java
new file mode 100644
index 0000000..560d5a7
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/jdi/ThreadGroupReferenceProxyImpl.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * @author Eugene Zhuravlev
+ */
+package com.intellij.debugger.jdi;
+
+import com.intellij.debugger.engine.jdi.ThreadGroupReferenceProxy;
+import com.intellij.openapi.diagnostic.Logger;
+import com.sun.jdi.ThreadGroupReference;
+import com.sun.jdi.ThreadReference;
+import org.jetbrains.annotations.NonNls;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public class ThreadGroupReferenceProxyImpl extends ObjectReferenceProxyImpl implements ThreadGroupReferenceProxy{
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.jdi.ThreadGroupReferenceProxyImpl");
+  //caches
+  private ThreadGroupReferenceProxyImpl myParentThreadGroupProxy;
+  private boolean myIsParentGroupCached = false;
+  private String myName;
+
+  public ThreadGroupReferenceProxyImpl(VirtualMachineProxyImpl virtualMachineProxy, ThreadGroupReference threadGroupReference) {
+    super(virtualMachineProxy, threadGroupReference);
+  }
+
+  public ThreadGroupReference getThreadGroupReference() {
+    return (ThreadGroupReference)getObjectReference();
+  }
+
+  public String name() {
+    checkValid();
+    if (myName == null) {
+      myName = getThreadGroupReference().name();
+    }
+    return myName;
+  }
+
+  public ThreadGroupReferenceProxyImpl parent() {
+    checkValid();
+    if (!myIsParentGroupCached) {
+      myParentThreadGroupProxy = getVirtualMachineProxy().getThreadGroupReferenceProxy(getThreadGroupReference().parent());
+      myIsParentGroupCached = true;
+    }
+    return myParentThreadGroupProxy;
+  }
+
+  public @NonNls String toString() {
+    return "ThreadGroupReferenceProxy: " + getThreadGroupReference().toString();
+  }
+
+  public void suspend() {
+    getThreadGroupReference().suspend();
+  }
+
+  public void resume() {
+    getThreadGroupReference().resume();
+  }
+
+  public List<ThreadReferenceProxyImpl> threads() {
+    List<ThreadReference> list = getThreadGroupReference().threads();
+    List<ThreadReferenceProxyImpl> proxies = new ArrayList<ThreadReferenceProxyImpl>(list.size());
+
+    for (Iterator<ThreadReference> iterator = list.iterator(); iterator.hasNext();) {
+      ThreadReference threadReference = iterator.next();
+      proxies.add(getVirtualMachineProxy().getThreadReferenceProxy(threadReference));
+    }
+    return proxies;
+  }
+
+  public List<ThreadGroupReferenceProxyImpl> threadGroups() {
+    List<ThreadGroupReference> list = getThreadGroupReference().threadGroups();
+    List<ThreadGroupReferenceProxyImpl> proxies = new ArrayList<ThreadGroupReferenceProxyImpl>(list.size());
+
+    for (Iterator<ThreadGroupReference> iterator = list.iterator(); iterator.hasNext();) {
+      ThreadGroupReference threadGroupReference = iterator.next();
+      proxies.add(getVirtualMachineProxy().getThreadGroupReferenceProxy(threadGroupReference));
+    }
+    return proxies;
+  }
+
+  public void clearCaches() {
+//    myIsParentGroupCached = false;
+//    myName = null;
+//    myParentThreadGroupProxy = null;
+    super.clearCaches();
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/jdi/ThreadReferenceProxyImpl.java b/java/debugger/impl/src/com/intellij/debugger/jdi/ThreadReferenceProxyImpl.java
new file mode 100644
index 0000000..25d08bb
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/jdi/ThreadReferenceProxyImpl.java
@@ -0,0 +1,289 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * @author Eugene Zhuravlev
+ */
+package com.intellij.debugger.jdi;
+
+import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.engine.jdi.ThreadReferenceProxy;
+import com.intellij.openapi.diagnostic.Logger;
+import com.sun.jdi.*;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.*;
+
+public final class ThreadReferenceProxyImpl extends ObjectReferenceProxyImpl implements ThreadReferenceProxy {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.jdi.ThreadReferenceProxyImpl");
+  // cached data
+  private String myName;
+  private int                       myFrameCount = -1;
+  // stackframes, 0 - bottom
+  private final List<StackFrameProxyImpl> myFramesFromBottom = new ArrayList<StackFrameProxyImpl>();
+  //cache build on the base of myFramesFromBottom 0 - top, initially nothing is cached
+  private List<StackFrameProxyImpl> myFrames = null;
+
+  private ThreadGroupReferenceProxyImpl myThreadGroupProxy;
+
+  public static Comparator<ThreadReferenceProxyImpl> ourComparator = new Comparator<ThreadReferenceProxyImpl>() {
+    public int compare(ThreadReferenceProxyImpl th1, ThreadReferenceProxyImpl th2) {
+      return th1.name().compareToIgnoreCase(th2.name());
+    }
+  };
+
+  public ThreadReferenceProxyImpl(VirtualMachineProxyImpl virtualMachineProxy, ThreadReference threadReference) {
+    super(virtualMachineProxy, threadReference);
+  }
+
+  public ThreadReference getThreadReference() {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    return (ThreadReference)getObjectReference();
+  }
+
+  public VirtualMachineProxyImpl getVirtualMachine() {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    return (VirtualMachineProxyImpl) myTimer;
+  }
+
+  public String name() {
+    checkValid();
+    if (myName == null) {
+      try {
+        myName = getThreadReference().name();
+      }
+      catch (ObjectCollectedException e) {
+        myName = "";
+      }
+      catch (IllegalThreadStateException e) {
+        myName = "zombie";
+      }                    
+    }
+    return myName;
+  }
+
+  public int getSuspendCount() {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    //LOG.assertTrue((mySuspendCount > 0) == suspends());
+    try {
+      return getThreadReference().suspendCount();
+    }
+    catch (ObjectCollectedException e) {
+      return 0;
+    }
+  }
+
+  public void suspend() {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    try {
+      getThreadReference().suspend();
+    }
+    catch (ObjectCollectedException ignored) {
+    }
+    clearCaches();
+  }
+
+  @NonNls
+  public String toString() {
+    //noinspection HardCodedStringLiteral
+    @NonNls String threadRefString;
+    try {
+      threadRefString = getThreadReference().toString() ;
+    }
+    catch (ObjectCollectedException e) {
+      threadRefString = "[thread collected]";
+    }
+    return "ThreadReferenceProxyImpl: " + threadRefString + " " + super.toString();
+  }
+
+  public void resume() {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    //JDI clears all caches on thread resume !!
+    final ThreadReference threadRef = getThreadReference();
+    if(LOG.isDebugEnabled()) {
+      LOG.debug("before resume" + threadRef);
+    }
+    getVirtualMachineProxy().clearCaches();
+    try {
+      threadRef.resume();
+    }
+    catch (ObjectCollectedException ignored) {
+    }
+  }
+
+  protected void clearCaches() {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    myFrames = null;
+    myFrameCount = -1;
+    super.clearCaches();
+  }
+
+  public int status() {
+    try {
+      return getThreadReference().status();
+    }
+    catch (ObjectCollectedException e) {
+      return ThreadReference.THREAD_STATUS_ZOMBIE;
+    }
+  }
+
+  public ThreadGroupReferenceProxyImpl threadGroupProxy() {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    checkValid();
+    if(myThreadGroupProxy == null) {
+      ThreadGroupReference threadGroupRef;
+      try {
+        threadGroupRef = getThreadReference().threadGroup();
+      }
+      catch (ObjectCollectedException e) {
+        threadGroupRef = null;
+      }
+      myThreadGroupProxy = getVirtualMachineProxy().getThreadGroupReferenceProxy(threadGroupRef);
+    }
+    return myThreadGroupProxy;
+  }
+
+  public int frameCount() throws EvaluateException {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    checkValid();
+    if (myFrameCount == -1) {
+      final ThreadReference threadReference = getThreadReference();
+      try {
+        myFrameCount = threadReference.frameCount();
+      }
+      catch(ObjectCollectedException e) {
+        myFrameCount = 0;
+      }
+      catch (IncompatibleThreadStateException e) {
+        if (!threadReference.isSuspended()) {
+          // give up because it seems to be really resumed
+          throw EvaluateExceptionUtil.createEvaluateException(e);
+        }
+        else {
+          // JDI bug: although isSuspended() == true, frameCount() may throw IncompatibleThreadStateException
+          // see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4783403
+          // unfortunately, impossible to get this information at the moment, so assume the frame count is null
+          myFrameCount = 0;
+        }
+      }
+    }
+    return myFrameCount;
+  }
+
+  public List<StackFrameProxyImpl> frames() throws EvaluateException {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    final ThreadReference threadRef = getThreadReference();
+    try {
+      //LOG.assertTrue(threadRef.isSuspended());
+      checkValid();
+
+      if(myFrames == null) {
+        checkFrames(threadRef);
+  
+        myFrames = new ArrayList<StackFrameProxyImpl>(frameCount());
+        for (ListIterator<StackFrameProxyImpl> iterator = myFramesFromBottom.listIterator(frameCount()); iterator.hasPrevious();) {
+          StackFrameProxyImpl stackFrameProxy = iterator.previous();
+          myFrames.add(stackFrameProxy);
+        }
+      }
+    }
+    catch (ObjectCollectedException e) {
+      return Collections.emptyList();
+    }
+    return myFrames;
+  }
+
+  private void checkFrames(@NotNull final ThreadReference threadRef) throws EvaluateException {
+    if (myFramesFromBottom.size() < frameCount()) {
+      int count = frameCount();
+      List<StackFrame> frames;
+      try {
+        frames = threadRef.frames(0, count - myFramesFromBottom.size());
+      }
+      catch (IncompatibleThreadStateException e) {
+        throw EvaluateExceptionUtil.createEvaluateException(e);
+      }
+      catch (InternalException e) {
+        throw EvaluateExceptionUtil.createEvaluateException(e);
+      }
+
+      int index = myFramesFromBottom.size() + 1;
+      for (ListIterator<StackFrame> iterator = frames.listIterator(count - myFramesFromBottom.size()); iterator.hasPrevious();) {
+        StackFrame stackFrame = iterator.previous();
+        myFramesFromBottom.add(new StackFrameProxyImpl(this, stackFrame, index));
+        index++;
+      }
+    }
+  }
+
+  public StackFrameProxyImpl frame(int i) throws EvaluateException {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    final ThreadReference threadReference = getThreadReference();
+    try {
+      if(!threadReference.isSuspended()) {
+        return null;
+      }
+      checkFrames(threadReference);
+      final int frameCount = frameCount();
+      if (frameCount == 0) {
+        return null;
+      }
+      return myFramesFromBottom.get(frameCount - i  - 1);
+    }
+    catch (ObjectCollectedException e) {
+      return null;
+    }
+    catch (IllegalThreadStateException e) {
+      return null;
+    }
+  }
+
+  public void popFrames(StackFrameProxyImpl stackFrame) throws EvaluateException {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    try {
+      getThreadReference().popFrames(stackFrame.getStackFrame());
+    }
+    catch (InvalidStackFrameException ignored) {
+    }
+    catch (ObjectCollectedException ignored) {
+    }
+    catch (InternalException e) {
+      throw EvaluateExceptionUtil.createEvaluateException(e);
+    }
+    catch (IncompatibleThreadStateException e) {
+      throw EvaluateExceptionUtil.createEvaluateException(e);
+    }
+    finally {
+      clearCaches();
+      getVirtualMachineProxy().clearCaches();
+    }
+  }
+
+  public boolean isSuspended() throws ObjectCollectedException {
+    try {
+      DebuggerManagerThreadImpl.assertIsManagerThread();
+      return getThreadReference().isSuspended();
+    }
+    catch (IllegalThreadStateException e) {
+      // must be zombie thread
+      LOG.info(e);
+      return false;
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/jdi/VirtualMachineProxyImpl.java b/java/debugger/impl/src/com/intellij/debugger/jdi/VirtualMachineProxyImpl.java
new file mode 100644
index 0000000..2b4c6b4
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/jdi/VirtualMachineProxyImpl.java
@@ -0,0 +1,678 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * @author Eugene Zhuravlev
+ */
+package com.intellij.debugger.jdi;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.DebugProcess;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.engine.jdi.VirtualMachineProxy;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.util.containers.HashMap;
+import com.sun.jdi.*;
+import com.sun.jdi.event.EventQueue;
+import com.sun.jdi.request.EventRequestManager;
+import com.sun.tools.jdi.VoidValueImpl;
+import org.jetbrains.annotations.NotNull;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.*;
+
+public class VirtualMachineProxyImpl implements JdiTimer, VirtualMachineProxy {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.jdi.VirtualMachineProxyImpl");
+  private final DebugProcessImpl myDebugProcess;
+  private final VirtualMachine myVirtualMachine;
+  private int myTimeStamp = 0;
+  private int myPausePressedCount = 0;
+
+  // cached data
+  private final Map<ObjectReference, ObjectReferenceProxyImpl>  myObjectReferenceProxies = new HashMap<ObjectReference, ObjectReferenceProxyImpl>();
+  private Map<ThreadReference, ThreadReferenceProxyImpl>  myAllThreads = new HashMap<ThreadReference, ThreadReferenceProxyImpl>();
+  private final Map<ThreadGroupReference, ThreadGroupReferenceProxyImpl> myThreadGroups = new HashMap<ThreadGroupReference, ThreadGroupReferenceProxyImpl>();
+  private boolean myAllThreadsDirty = true;
+  private List<ReferenceType> myAllClasses;
+  private Map<ReferenceType, List<ReferenceType>> myNestedClassesCache = new HashMap<ReferenceType, List<ReferenceType>>();
+
+  public Throwable mySuspendLogger = new Throwable();
+  private final boolean myVersionHigher_15;
+  private final boolean myVersionHigher_14;
+
+  public VirtualMachineProxyImpl(DebugProcessImpl debugProcess, @NotNull VirtualMachine virtualMachine) {
+    myVirtualMachine = virtualMachine;
+    myDebugProcess = debugProcess;
+
+    myVersionHigher_15 = versionHigher("1.5");
+    myVersionHigher_14 = myVersionHigher_15 || versionHigher("1.4");
+
+    // avoid lazy-init for some properties: the following will pre-calculate values
+    canRedefineClasses();
+    canWatchFieldModification();
+    canPopFrames();
+
+    List<ThreadGroupReference> groups = virtualMachine.topLevelThreadGroups();
+    for (ThreadGroupReference threadGroupReference : groups) {
+      threadGroupCreated(threadGroupReference);
+    }
+  }
+
+  public VirtualMachine getVirtualMachine() {
+    return myVirtualMachine;
+  }
+
+  public List<ReferenceType> classesByName(String s) {
+    return myVirtualMachine.classesByName(s);
+  }
+
+  public List<ReferenceType> nestedTypes(ReferenceType refType) {
+    List<ReferenceType> nestedTypes = myNestedClassesCache.get(refType);
+    if (nestedTypes == null) {
+      final List<ReferenceType> list = refType.nestedTypes();
+      final int size = list.size();
+      if (size > 0) {
+        final Set<ReferenceType> candidates = new HashSet<ReferenceType>();
+        final ClassLoaderReference outerLoader = refType.classLoader();
+        for (ReferenceType nested : list) {
+          try {
+            if (outerLoader == null? nested.classLoader() == null : outerLoader.equals(nested.classLoader())) {
+              candidates.add(nested);
+            }
+          }
+          catch (ObjectCollectedException ignored) {
+          }
+        }
+
+        if (!candidates.isEmpty()) {
+          // keep only direct nested types
+          final Set<ReferenceType> nested2 = new HashSet<ReferenceType>();
+          for (final ReferenceType candidate : candidates) {
+            nested2.addAll(nestedTypes(candidate));
+          }
+          candidates.removeAll(nested2);
+        }
+        
+        nestedTypes = candidates.isEmpty()? Collections.<ReferenceType>emptyList() : new ArrayList<ReferenceType>(candidates);
+      }
+      else {
+        nestedTypes = Collections.emptyList();
+      }
+      myNestedClassesCache.put(refType, nestedTypes);
+    }
+    return nestedTypes;
+  }
+
+  public List<ReferenceType> allClasses() {
+    if (myAllClasses == null) {
+      myAllClasses = myVirtualMachine.allClasses();
+    }
+    return myAllClasses;
+  }
+
+  public String toString() {
+    return myVirtualMachine.toString();
+  }
+
+  public void redefineClasses(Map<ReferenceType, byte[]> map) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    try {
+      myVirtualMachine.redefineClasses(map);
+    }
+    finally {
+      clearCaches();
+    }
+  }
+
+  /**
+   * @return a list of all ThreadReferenceProxies
+   */
+  public Collection<ThreadReferenceProxyImpl> allThreads() {
+    if(myAllThreadsDirty) {
+      myAllThreadsDirty = false;
+
+      final List<ThreadReference> currentThreads = myVirtualMachine.allThreads();
+      final Map<ThreadReference, ThreadReferenceProxyImpl> result = new HashMap<ThreadReference, ThreadReferenceProxyImpl>();
+
+      for (final ThreadReference threadReference : currentThreads) {
+        ThreadReferenceProxyImpl proxy = myAllThreads.get(threadReference);
+        if(proxy == null) {
+          proxy = new ThreadReferenceProxyImpl(this, threadReference);
+        }
+        result.put(threadReference, proxy);
+      }
+      myAllThreads = result;
+    }
+
+    return myAllThreads.values();
+  }
+
+  public void threadStarted(ThreadReference thread) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    final Map<ThreadReference, ThreadReferenceProxyImpl> allThreads = myAllThreads;
+    if (allThreads != null && !allThreads.containsKey(thread)) {
+      allThreads.put(thread, new ThreadReferenceProxyImpl(this, thread));
+    }
+  }
+
+  public void threadStopped(ThreadReference thread) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    final Map<ThreadReference, ThreadReferenceProxyImpl> allThreads = myAllThreads;
+    if (allThreads != null) {
+      allThreads.remove(thread);
+    }
+  }
+
+  public void suspend() {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    myPausePressedCount++;
+    myVirtualMachine.suspend();
+    clearCaches();
+  }
+
+  public void resume() {    
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    if (myPausePressedCount > 0) {
+      myPausePressedCount--;
+    }
+    clearCaches();
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("before resume VM");
+    }
+    try {
+      myVirtualMachine.resume();
+    }
+    catch (InternalException e) {
+      // ok to ignore. Although documentation says it is safe to invoke resume() on running VM,
+      // sometimes this leads to com.sun.jdi.InternalException: Unexpected JDWP Error: 13 (THREAD_NOT_SUSPENDED)
+      LOG.info(e);
+    }
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("VM resumed");
+    }
+    //logThreads();
+  }
+
+  /**
+   * @return a list of threadGroupProxies
+   */
+  public List<ThreadGroupReferenceProxyImpl> topLevelThreadGroups() {
+    List<ThreadGroupReference> list = getVirtualMachine().topLevelThreadGroups();
+
+    List<ThreadGroupReferenceProxyImpl> result = new ArrayList<ThreadGroupReferenceProxyImpl>(list.size());
+
+    for (ThreadGroupReference threadGroup : list) {
+      result.add(getThreadGroupReferenceProxy(threadGroup));
+    }
+
+    return result;
+  }
+
+  public void threadGroupCreated(ThreadGroupReference threadGroupReference){
+    if(!isJ2ME()) {
+      ThreadGroupReferenceProxyImpl proxy = new ThreadGroupReferenceProxyImpl(this, threadGroupReference);
+      myThreadGroups.put(threadGroupReference, proxy);
+    }
+  }
+
+  public boolean isJ2ME() {
+    return isJ2ME(getVirtualMachine());
+  }
+
+  private static boolean isJ2ME(VirtualMachine virtualMachine) {
+    return virtualMachine.version().startsWith("1.0");
+  }
+
+  public void threadGroupRemoved(ThreadGroupReference threadGroupReference){
+    myThreadGroups.remove(threadGroupReference);
+  }
+
+  public EventQueue eventQueue() {
+    return myVirtualMachine.eventQueue();
+  }
+
+  public EventRequestManager eventRequestManager() {
+    return myVirtualMachine.eventRequestManager();
+  }
+
+  public VoidValue mirrorOf() throws EvaluateException {
+    try {
+      Constructor<VoidValueImpl> constructor = VoidValueImpl.class.getDeclaredConstructor(new Class[]{VirtualMachine.class});
+      constructor.setAccessible(true);
+      return constructor.newInstance(myVirtualMachine);
+    }
+    catch (NoSuchMethodException e) {
+      LOG.error(e);
+    }
+    catch (IllegalAccessException e) {
+      LOG.error(e);
+    }
+    catch (InvocationTargetException e) {
+      LOG.error(e);
+    }
+    catch (InstantiationException e) {
+      LOG.error(e);
+    }
+    throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("error.cannot.create.void.value"));
+  }
+
+  public BooleanValue mirrorOf(boolean b) {
+    return myVirtualMachine.mirrorOf(b);
+  }
+
+  public ByteValue mirrorOf(byte b) {
+    return myVirtualMachine.mirrorOf(b);
+  }
+
+  public CharValue mirrorOf(char c) {
+    return myVirtualMachine.mirrorOf(c);
+  }
+
+  public ShortValue mirrorOf(short i) {
+    return myVirtualMachine.mirrorOf(i);
+  }
+
+  public IntegerValue mirrorOf(int i) {
+    return myVirtualMachine.mirrorOf(i);
+  }
+
+  public LongValue mirrorOf(long l) {
+    return myVirtualMachine.mirrorOf(l);
+  }
+
+  public FloatValue mirrorOf(float v) {
+    return myVirtualMachine.mirrorOf(v);
+  }
+
+  public DoubleValue mirrorOf(double v) {
+    return myVirtualMachine.mirrorOf(v);
+  }
+
+  public StringReference mirrorOf(String s) {
+    return myVirtualMachine.mirrorOf(s);
+  }
+
+  public Process process() {
+    return myVirtualMachine.process();
+  }
+
+  public void dispose() {
+    myVirtualMachine.dispose();
+  }
+
+  public void exit(int i) {
+    myVirtualMachine.exit(i);
+  }
+
+  private final Capability myWatchFielsModification = new Capability() {
+    protected boolean calcValue() {
+      return myVirtualMachine.canWatchFieldModification();
+    }
+  };
+  public boolean canWatchFieldModification() {
+    return myWatchFielsModification.isAvailable();
+  }
+
+  private final Capability myWatchFieldAccess = new Capability() {
+    protected boolean calcValue() {
+      return myVirtualMachine.canWatchFieldAccess();
+    }
+  };
+  public boolean canWatchFieldAccess() {
+    return myWatchFieldAccess.isAvailable();
+  }
+
+  private final Capability myInvokeMethods = new Capability() {
+    protected boolean calcValue() {
+      return isJ2ME();
+    }
+  };
+  public boolean canInvokeMethods() {
+    return myInvokeMethods.isAvailable();
+  }
+
+  private final Capability myGetBytecodes = new Capability() {
+    protected boolean calcValue() {
+      return myVirtualMachine.canGetBytecodes();
+    }
+  };
+  public boolean canGetBytecodes() {
+    return myGetBytecodes.isAvailable();
+  }
+
+  private final Capability myGetSyntheticAttribute = new Capability() {
+    protected boolean calcValue() {
+      return myVirtualMachine.canGetSyntheticAttribute();
+    }
+  };
+  public boolean canGetSyntheticAttribute() {
+    return myGetSyntheticAttribute.isAvailable();
+  }
+
+  private final Capability myGetOwnedMonitorInfo = new Capability() {
+    protected boolean calcValue() {
+      return myVirtualMachine.canGetOwnedMonitorInfo();
+    }
+  };
+  public boolean canGetOwnedMonitorInfo() {
+    return myGetOwnedMonitorInfo.isAvailable();
+  }
+
+  private final Capability myGetMonitorFrameInfo = new Capability() {
+    protected boolean calcValue() {
+      return myVirtualMachine.canGetMonitorFrameInfo();
+    }
+  };
+  public boolean canGetMonitorFrameInfo() {
+      return myGetMonitorFrameInfo.isAvailable();
+  }
+  
+  private final Capability myGetCurrentContendedMonitor = new Capability() {
+    protected boolean calcValue() {
+      return myVirtualMachine.canGetCurrentContendedMonitor();
+    }
+  };
+  public boolean canGetCurrentContendedMonitor() {
+    return myGetCurrentContendedMonitor.isAvailable();
+  }
+
+  private final Capability myGetMonitorInfo = new Capability() {
+    protected boolean calcValue() {
+      return myVirtualMachine.canGetMonitorInfo();
+    }
+  };
+  public boolean canGetMonitorInfo() {
+    return myGetMonitorInfo.isAvailable();
+  }
+
+  private final Capability myUseInstanceFilters = new Capability() {
+    protected boolean calcValue() {
+      return myVersionHigher_14 && myVirtualMachine.canUseInstanceFilters();
+    }
+  };
+  public boolean canUseInstanceFilters() {
+    return myUseInstanceFilters.isAvailable();
+  }
+
+  private final Capability myRedefineClasses = new Capability() {
+    protected boolean calcValue() {
+      return myVersionHigher_14 && myVirtualMachine.canRedefineClasses();
+    }
+  };
+  public boolean canRedefineClasses() {
+    return myRedefineClasses.isAvailable();
+  }
+
+  private final Capability myAddMethod = new Capability() {
+    protected boolean calcValue() {
+      return myVersionHigher_14 && myVirtualMachine.canAddMethod();
+    }
+  };
+  public boolean canAddMethod() {
+    return myAddMethod.isAvailable();
+  }
+
+  private final Capability myUnrestrictedlyRedefineClasses = new Capability() {
+    protected boolean calcValue() {
+      return myVersionHigher_14 && myVirtualMachine.canUnrestrictedlyRedefineClasses();
+    }
+  };
+  public boolean canUnrestrictedlyRedefineClasses() {
+    return myUnrestrictedlyRedefineClasses.isAvailable();
+  }
+
+  private final Capability myPopFrames = new Capability() {
+    protected boolean calcValue() {
+      return myVersionHigher_14 && myVirtualMachine.canPopFrames();
+    }
+  };
+  public boolean canPopFrames() {
+    return myPopFrames.isAvailable();
+  }
+
+  private final Capability myCanGetInstanceInfo = new Capability() {
+    protected boolean calcValue() {
+      if (!myVersionHigher_15) {
+        return false;
+      }
+      try {
+        final Method method = VirtualMachine.class.getMethod("canGetInstanceInfo");
+        return (Boolean)method.invoke(myVirtualMachine);
+      }
+      catch (NoSuchMethodException ignored) {
+      }
+      catch (IllegalAccessException e) {
+        LOG.error(e);
+      }
+      catch (InvocationTargetException e) {
+        LOG.error(e);
+      }
+      return false;
+    }
+  };
+  public boolean canGetInstanceInfo() {
+    return myCanGetInstanceInfo.isAvailable();
+  }
+
+  public final boolean versionHigher(String version) {
+    return myVirtualMachine.version().compareTo(version) >= 0;
+  }
+
+  private final Capability myGetSourceDebugExtension = new Capability() {
+    protected boolean calcValue() {
+      return myVersionHigher_14 && myVirtualMachine.canGetSourceDebugExtension();
+    }
+  };
+  public boolean canGetSourceDebugExtension() {
+    return myGetSourceDebugExtension.isAvailable();
+  }
+
+  private final Capability myRequestVMDeathEvent = new Capability() {
+    protected boolean calcValue() {
+      return myVersionHigher_14 && myVirtualMachine.canRequestVMDeathEvent();
+    }
+  };
+  public boolean canRequestVMDeathEvent() {
+    return myRequestVMDeathEvent.isAvailable();
+  }
+
+  private final Capability myGetMethodReturnValues = new Capability() {
+    protected boolean calcValue() {
+      if (myVersionHigher_15) {
+        //return myVirtualMachine.canGetMethodReturnValues();
+        try {
+          //noinspection HardCodedStringLiteral
+          final Method method = VirtualMachine.class.getDeclaredMethod("canGetMethodReturnValues");
+          final Boolean rv = (Boolean)method.invoke(myVirtualMachine);
+          return rv.booleanValue();
+        }
+        catch (NoSuchMethodException ignored) {
+        }
+        catch (IllegalAccessException ignored) {
+        }
+        catch (InvocationTargetException ignored) {
+        }
+      }
+      return false;
+    }
+  };
+  public boolean canGetMethodReturnValues() {
+    return myGetMethodReturnValues.isAvailable();
+  }
+
+  public String getDefaultStratum() {
+    return myVersionHigher_14 ? myVirtualMachine.getDefaultStratum() : null;
+  }
+
+  public String description() {
+    return myVirtualMachine.description();
+  }
+
+  public String version() {
+    return myVirtualMachine.version();
+  }
+
+  public String name() {
+    return myVirtualMachine.name();
+  }
+
+  public void setDebugTraceMode(int i) {
+    myVirtualMachine.setDebugTraceMode(i);
+  }
+
+  public ThreadReferenceProxyImpl getThreadReferenceProxy(ThreadReference thread) {
+    if(thread == null) {
+      return null;
+    }
+
+    ThreadReferenceProxyImpl proxy = myAllThreads.get(thread);
+    if(proxy == null) {
+      proxy = new ThreadReferenceProxyImpl(this, thread);
+      myAllThreads.put(thread, proxy);
+    }
+
+    return proxy;
+  }
+
+  public ThreadGroupReferenceProxyImpl getThreadGroupReferenceProxy(ThreadGroupReference group) {
+    if(group == null) {
+      return null;
+    }
+
+    ThreadGroupReferenceProxyImpl proxy = myThreadGroups.get(group);
+    if(proxy == null) {
+      if(!isJ2ME()) {
+        proxy = new ThreadGroupReferenceProxyImpl(this, group);
+        myThreadGroups.put(group, proxy);
+      }
+    }
+
+    return proxy;
+  }
+
+  public ObjectReferenceProxyImpl getObjectReferenceProxy(ObjectReference objectReference) {
+    if (objectReference != null) {
+      if (objectReference instanceof ThreadReference) {
+        return getThreadReferenceProxy((ThreadReference)objectReference);
+      }
+      else if (objectReference instanceof ThreadGroupReference) {
+        return getThreadGroupReferenceProxy((ThreadGroupReference)objectReference);
+      }
+      else {
+        ObjectReferenceProxyImpl proxy = myObjectReferenceProxies.get(objectReference);
+        if (proxy == null) {
+          if (objectReference instanceof StringReference) {
+            proxy = new StringReferenceProxy(this, (StringReference)objectReference);
+          }
+          else {
+            proxy = new ObjectReferenceProxyImpl(this, objectReference);
+          }
+          myObjectReferenceProxies.put(objectReference, proxy);
+        }
+        return proxy;
+      }
+    }
+    return null;
+  }
+
+  public boolean equals(Object obj) {
+    LOG.assertTrue(obj instanceof VirtualMachineProxyImpl);
+    return myVirtualMachine.equals(((VirtualMachineProxyImpl)obj).getVirtualMachine());
+  }
+
+  public int hashCode() {
+    return myVirtualMachine.hashCode();
+  }
+
+  public void clearCaches() {
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("VM cleared");
+    }
+
+    myAllClasses = null;
+    if (!myNestedClassesCache.isEmpty()) {
+      myNestedClassesCache = new HashMap<ReferenceType, List<ReferenceType>>(myNestedClassesCache.size());
+    }
+    //myAllThreadsDirty = true;
+    myTimeStamp++;
+  }
+
+  public int getCurrentTime() {
+    return myTimeStamp;
+  }
+
+  public DebugProcess getDebugProcess() {
+    return myDebugProcess;
+  }
+
+  public static boolean isCollected(ObjectReference reference) {
+    return !isJ2ME(reference.virtualMachine()) && reference.isCollected();
+  }
+
+  public String getResumeStack() {
+    return StringUtil.getThrowableText(mySuspendLogger);
+  }
+
+  public boolean isPausePressed() {
+    return myPausePressedCount > 0;
+  }
+
+  public boolean isSuspended() {
+    for (ThreadReferenceProxyImpl thread : allThreads()) {
+      if (thread.getSuspendCount() != 0) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  public void logThreads() {
+    if(LOG.isDebugEnabled()) {
+      for (ThreadReferenceProxyImpl thread : allThreads()) {
+        if (!thread.isCollected()) {
+          LOG.debug("suspends " + thread + " " + thread.getSuspendCount() + " " + thread.isSuspended());
+        }
+      }
+    }
+  }
+
+
+  private abstract static class Capability {
+    private Boolean myValue = null;
+
+    public final boolean isAvailable() {
+      if (myValue == null) {
+        try {
+          myValue = Boolean.valueOf(calcValue());
+        }
+        catch (VMDisconnectedException e) {
+          LOG.info(e);
+          myValue = Boolean.FALSE;
+        }
+      }
+      return myValue.booleanValue();
+    }
+
+    protected abstract boolean calcValue();
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/ArrayRendererConfigurable.java b/java/debugger/impl/src/com/intellij/debugger/settings/ArrayRendererConfigurable.java
new file mode 100644
index 0000000..eeb0986
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/settings/ArrayRendererConfigurable.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2000-2009 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.debugger.settings;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.ui.tree.render.ArrayRenderer;
+import com.intellij.openapi.application.ApplicationNamesInfo;
+import com.intellij.openapi.options.UnnamedConfigurable;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.openapi.ui.Messages;
+
+import javax.swing.*;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import java.awt.*;
+
+public class ArrayRendererConfigurable implements UnnamedConfigurable{
+  private JTextField myEntriesLimit;
+  private JTextField myStartIndex;
+  private JTextField myEndIndex;
+  private boolean myEntriesLimitUpdateEnabled = true;
+  private boolean myIndexUpdateEnabled = true;
+  
+  private final ArrayRenderer myRenderer;
+  private JComponent myPanel;
+
+  public ArrayRendererConfigurable(ArrayRenderer renderer) {
+    myRenderer = renderer;
+  }
+
+  public ArrayRenderer getRenderer() {
+    return myRenderer;
+  }
+
+  public void reset() {
+    myStartIndex.setText(String.valueOf(myRenderer.START_INDEX));
+    myEndIndex.setText(String.valueOf(myRenderer.END_INDEX));
+    myEntriesLimit.setText(String.valueOf(myRenderer.ENTRIES_LIMIT));
+  }
+
+  public void apply() {
+    applyTo(myRenderer, true);
+  }
+
+  private void applyTo(ArrayRenderer renderer, boolean showBigRangeWarning) {
+    int newStartIndex = getInt(myStartIndex);
+    int newEndIndex = getInt(myEndIndex);
+    int newLimit = getInt(myEntriesLimit);
+
+    if (newStartIndex >= 0 && newEndIndex >= 0) {
+      if (newStartIndex >= newEndIndex) {
+        int currentStartIndex = renderer.START_INDEX;
+        int currentEndIndex = renderer.END_INDEX;
+        newEndIndex = newStartIndex + (currentEndIndex - currentStartIndex);
+      }
+
+      if(newLimit <= 0) {
+        newLimit = 1;
+      }
+
+      if(showBigRangeWarning && (newEndIndex - newStartIndex > 10000)) {
+        final int answer = Messages.showOkCancelDialog(
+          myPanel.getRootPane(),
+          DebuggerBundle.message("warning.range.too.big", ApplicationNamesInfo.getInstance().getProductName()),
+          DebuggerBundle.message("title.range.too.big"),
+          Messages.getWarningIcon());
+        if(answer != DialogWrapper.OK_EXIT_CODE) {
+          return;
+        }
+      }
+    }
+
+    renderer.START_INDEX   = newStartIndex;
+    renderer.END_INDEX     = newEndIndex;
+    renderer.ENTRIES_LIMIT = newLimit;
+  }
+
+  public JComponent createComponent() {
+    myPanel = new JPanel(new GridBagLayout());
+
+    myStartIndex = new JTextField(5);
+    myEndIndex = new JTextField(5);
+    myEntriesLimit = new JTextField(5);
+
+    final FontMetrics fontMetrics = myStartIndex.getFontMetrics(myStartIndex.getFont());
+    final Dimension minSize = new Dimension(myStartIndex.getPreferredSize());
+    //noinspection HardCodedStringLiteral
+    minSize.width = fontMetrics.stringWidth("AAAAA");
+    myStartIndex.setMinimumSize(minSize);
+    myEndIndex.setMinimumSize(minSize);
+    myEntriesLimit.setMinimumSize(minSize);
+
+    JLabel startIndexLabel = new JLabel(DebuggerBundle.message("label.array.renderer.configurable.start.index"));
+    startIndexLabel.setLabelFor(myStartIndex);
+
+    JLabel endIndexLabel = new JLabel(DebuggerBundle.message("label.array.renderer.configurable.end.index"));
+    endIndexLabel.setLabelFor(myEndIndex);
+
+    JLabel entriesLimitLabel = new JLabel(DebuggerBundle.message("label.array.renderer.configurable.max.count1"));
+    entriesLimitLabel.setLabelFor(myEntriesLimit);
+
+    myPanel.add(startIndexLabel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 8), 0, 0));
+    myPanel.add(myStartIndex, new GridBagConstraints(1, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 8), 0, 0));
+    myPanel.add(endIndexLabel, new GridBagConstraints(2, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 8), 0, 0));
+    myPanel.add(myEndIndex, new GridBagConstraints(3, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
+
+    myPanel.add(entriesLimitLabel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0.0, 1.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(4, 0, 0, 8), 0, 0));
+    myPanel.add(myEntriesLimit, new GridBagConstraints(1, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(4, 0, 0, 8), 0, 0));
+    myPanel.add(new JLabel(DebuggerBundle.message("label.array.renderer.configurable.max.count2")), new GridBagConstraints(2, GridBagConstraints.RELATIVE, 2, 1, 1.0, 1.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(4, 0, 0, 0), 0, 0));
+
+    final DocumentListener listener = new DocumentListener() {
+      private void updateEntriesLimit() {
+        final boolean state = myIndexUpdateEnabled;
+        myIndexUpdateEnabled = false;
+        try {
+          if (myEntriesLimitUpdateEnabled) {
+            myEntriesLimit.setText(String.valueOf(getInt(myEndIndex) - getInt(myStartIndex) + 1));
+          }
+        }
+        finally {
+          myIndexUpdateEnabled = state;
+        }
+      }
+      public void changedUpdate(DocumentEvent e) {
+        updateEntriesLimit();
+      }
+      public void insertUpdate (DocumentEvent e) {
+        updateEntriesLimit();
+      }
+      public void removeUpdate (DocumentEvent e) {
+        updateEntriesLimit();
+      }
+    };
+    myStartIndex.getDocument().addDocumentListener(listener);
+    myEndIndex.getDocument().addDocumentListener(listener);
+    myEntriesLimit.getDocument().addDocumentListener(new DocumentListener() {
+      private void updateEndIndex() {
+        final boolean state = myEntriesLimitUpdateEnabled;
+        myEntriesLimitUpdateEnabled = false;
+        try {
+          if (myIndexUpdateEnabled) {
+            myEndIndex.setText(String.valueOf(getInt(myEntriesLimit) + getInt(myStartIndex) - 1));
+          }
+        }
+        finally {
+          myEntriesLimitUpdateEnabled = state;
+        }
+      }
+      public void insertUpdate(DocumentEvent e) {
+        updateEndIndex();
+      }
+
+      public void removeUpdate(DocumentEvent e) {
+        updateEndIndex();
+      }
+
+      public void changedUpdate(DocumentEvent e) {
+        updateEndIndex();
+      }
+    });
+    return myPanel;
+  }
+
+  private static int getInt(JTextField textField) {
+    int newEndIndex = 0;
+    try {
+      newEndIndex = Integer.parseInt(textField.getText().trim());
+    }
+    catch (NumberFormatException exception) {
+      // ignored
+    }
+    return newEndIndex;
+  }
+
+  public boolean isModified() {
+    ArrayRenderer cloneRenderer = myRenderer.clone();
+    applyTo(cloneRenderer, false);
+    final boolean valuesEqual =
+      (myRenderer.END_INDEX == cloneRenderer.END_INDEX) &&
+      (myRenderer.START_INDEX == cloneRenderer.START_INDEX) &&
+      (myRenderer.ENTRIES_LIMIT == cloneRenderer.ENTRIES_LIMIT);
+    return !valuesEqual;
+  }
+
+  public void disposeUIResources() {
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/CompositeDataBinding.java b/java/debugger/impl/src/com/intellij/debugger/settings/CompositeDataBinding.java
new file mode 100644
index 0000000..896fe54
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/settings/CompositeDataBinding.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2000-2009 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.debugger.settings;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+/**
+ * @author Eugene Zhuravlev
+ * Date: Apr 12, 2005
+ */
+public class CompositeDataBinding implements DataBinding{
+  private final List<DataBinding> myBindings = new ArrayList<DataBinding>();
+
+  void addBinding(DataBinding binding) {
+    myBindings.add(binding);
+  }
+
+  public void loadData(Object from) {
+    for (Iterator<DataBinding> it = myBindings.iterator(); it.hasNext();) {
+      it.next().loadData(from);
+    }
+  }
+
+  public void saveData(Object to) {
+    for (Iterator<DataBinding> it = myBindings.iterator(); it.hasNext();) {
+      it.next().saveData(to);
+    }
+  }
+
+  public boolean isModified(Object obj) {
+    for (Iterator<DataBinding> it = myBindings.iterator(); it.hasNext();) {
+      if (it.next().isModified(obj)) {
+        return true;
+      }
+    }
+    return false;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/CompoundRendererConfigurable.java b/java/debugger/impl/src/com/intellij/debugger/settings/CompoundRendererConfigurable.java
new file mode 100644
index 0000000..2f92bc5
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/settings/CompoundRendererConfigurable.java
@@ -0,0 +1,497 @@
+/*
+ * Copyright 2000-2009 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.debugger.settings;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.DebuggerUtils;
+import com.intellij.debugger.engine.JVMNameUtil;
+import com.intellij.debugger.engine.evaluation.CodeFragmentKind;
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.debugger.engine.evaluation.TextWithImportsImpl;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.ui.DebuggerExpressionTextField;
+import com.intellij.debugger.ui.JavaDebuggerSupport;
+import com.intellij.debugger.ui.tree.render.*;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.options.ConfigurationException;
+import com.intellij.openapi.options.UnnamedConfigurable;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.TextFieldWithBrowseButton;
+import com.intellij.openapi.util.Pair;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.ui.AnActionButton;
+import com.intellij.ui.AnActionButtonRunnable;
+import com.intellij.ui.TableUtil;
+import com.intellij.ui.ToolbarDecorator;
+import com.intellij.ui.table.JBTable;
+import com.intellij.util.ui.AbstractTableCellEditor;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.DefaultTableCellRenderer;
+import javax.swing.table.TableColumn;
+import java.awt.*;
+import java.awt.event.*;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: Feb 24, 2005
+ */
+public class CompoundRendererConfigurable implements UnnamedConfigurable {
+  private CompoundReferenceRenderer myRenderer;
+  private CompoundReferenceRenderer myOriginalRenderer;
+  private Project myProject;
+  private TextFieldWithBrowseButton myClassNameField;
+  private JRadioButton myRbDefaultLabel;
+  private JRadioButton myRbExpressionLabel;
+  private JRadioButton myRbDefaultChildrenRenderer;
+  private JRadioButton myRbExpressionChildrenRenderer;
+  private JRadioButton myRbListChildrenRenderer;
+  private DebuggerExpressionTextField myLabelEditor;
+  private DebuggerExpressionTextField myChildrenEditor;
+  private DebuggerExpressionTextField myChildrenExpandedEditor;
+  private DebuggerExpressionTextField myListChildrenEditor;
+  private JComponent myChildrenListEditor;
+  private JLabel myExpandedLabel;
+  private JPanel myMainPanel;
+  private JBTable myTable;
+  @NonNls private static final String EMPTY_PANEL_ID = "EMPTY";
+  @NonNls private static final String DATA_PANEL_ID = "DATA";
+  private static final int NAME_TABLE_COLUMN = 0;
+  private static final int EXPRESSION_TABLE_COLUMN = 1;
+
+  public CompoundRendererConfigurable(@Nullable Project project) {
+    myProject = project;
+  }
+
+  public void setRenderer(NodeRenderer renderer) {
+    if (renderer instanceof CompoundReferenceRenderer) {
+      myRenderer = (CompoundReferenceRenderer)renderer;
+      myOriginalRenderer = (CompoundReferenceRenderer)renderer.clone();
+    }
+    else {
+      myRenderer = myOriginalRenderer = null;
+    }
+    reset();
+  }
+
+  public CompoundReferenceRenderer getRenderer() {
+    return myRenderer;
+  }
+
+  public JComponent createComponent() {
+    if (myProject == null) {
+      myProject = JavaDebuggerSupport.getCurrentProject();
+    }
+    final JPanel panel = new JPanel(new GridBagLayout());
+
+    myRbDefaultLabel = new JRadioButton(DebuggerBundle.message("label.compound.renderer.configurable.use.default.renderer"));
+    myRbExpressionLabel = new JRadioButton(DebuggerBundle.message("label.compound.renderer.configurable.use.expression"));
+    final ButtonGroup labelButtonsGroup = new ButtonGroup();
+    labelButtonsGroup.add(myRbDefaultLabel);
+    labelButtonsGroup.add(myRbExpressionLabel);
+
+    myRbDefaultChildrenRenderer = new JRadioButton(DebuggerBundle.message("label.compound.renderer.configurable.use.default.renderer"));
+    myRbExpressionChildrenRenderer = new JRadioButton(DebuggerBundle.message("label.compound.renderer.configurable.use.expression"));
+    myRbListChildrenRenderer = new JRadioButton(DebuggerBundle.message("label.compound.renderer.configurable.use.expression.list"));
+    final ButtonGroup childrenButtonGroup = new ButtonGroup();
+    childrenButtonGroup.add(myRbDefaultChildrenRenderer);
+    childrenButtonGroup.add(myRbExpressionChildrenRenderer);
+    childrenButtonGroup.add(myRbListChildrenRenderer);
+
+    myLabelEditor = new DebuggerExpressionTextField(myProject, null, "ClassLabelExpression");
+    myChildrenEditor = new DebuggerExpressionTextField(myProject, null, "ClassChildrenExpression");
+    myChildrenExpandedEditor = new DebuggerExpressionTextField(myProject, null, "ClassChildrenExpression");
+    myChildrenListEditor = createChildrenListEditor();
+
+    final ItemListener updateListener = new ItemListener() {
+      public void itemStateChanged(ItemEvent e) {
+        updateEnabledState();
+      }
+    };
+    myRbExpressionLabel.addItemListener(updateListener);
+    myRbListChildrenRenderer.addItemListener(updateListener);
+    myRbExpressionChildrenRenderer.addItemListener(updateListener);
+
+    myClassNameField = new TextFieldWithBrowseButton(new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        PsiClass psiClass = DebuggerUtils.getInstance()
+          .chooseClassDialog(DebuggerBundle.message("title.compound.renderer.configurable.choose.renderer.reference.type"), myProject);
+        if (psiClass != null) {
+          myClassNameField.setText(JVMNameUtil.getNonAnonymousClassName(psiClass));
+        }
+      }
+    });
+    myClassNameField.getTextField().addFocusListener(new FocusAdapter() {
+      public void focusLost(FocusEvent e) {
+        final String qName = myClassNameField.getText();
+        updateContext(qName);
+      }
+    });
+
+    panel.add(new JLabel(DebuggerBundle.message("label.compound.renderer.configurable.apply.to")),
+              new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE,
+                                     new Insets(0, 0, 0, 0), 0, 0));
+    panel.add(myClassNameField, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST,
+                                                       GridBagConstraints.HORIZONTAL, new Insets(4, 0, 0, 0), 0, 0));
+
+    panel.add(new JLabel(DebuggerBundle.message("label.compound.renderer.configurable.when.rendering")),
+              new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE,
+                                     new Insets(20, 0, 0, 0), 0, 0));
+    panel.add(myRbDefaultLabel,
+              new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE,
+                                     new Insets(0, 10, 0, 0), 0, 0));
+    panel.add(myRbExpressionLabel,
+              new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE,
+                                     new Insets(0, 10, 0, 0), 0, 0));
+    panel.add(myLabelEditor, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST,
+                                                    GridBagConstraints.HORIZONTAL, new Insets(0, 30, 0, 0), 0, 0));
+
+    panel.add(new JLabel(DebuggerBundle.message("label.compound.renderer.configurable.when.expanding")),
+              new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE,
+                                     new Insets(20, 0, 0, 0), 0, 0));
+    panel.add(myRbDefaultChildrenRenderer,
+              new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE,
+                                     new Insets(0, 10, 0, 0), 0, 0));
+    panel.add(myRbExpressionChildrenRenderer,
+              new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE,
+                                     new Insets(0, 10, 0, 0), 0, 0));
+    panel.add(myChildrenEditor, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST,
+                                                       GridBagConstraints.HORIZONTAL, new Insets(0, 30, 0, 0), 0, 0));
+    myExpandedLabel = new JLabel(DebuggerBundle.message("label.compound.renderer.configurable.test.can.expand"));
+    panel.add(myExpandedLabel,
+              new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE,
+                                     new Insets(4, 30, 0, 0), 0, 0));
+    panel.add(myChildrenExpandedEditor, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST,
+                                                               GridBagConstraints.HORIZONTAL, new Insets(0, 30, 0, 0), 0, 0));
+    panel.add(myRbListChildrenRenderer, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST,
+                                                               GridBagConstraints.HORIZONTAL, new Insets(0, 10, 0, 0), 0, 0));
+    panel.add(myChildrenListEditor,
+              new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH,
+                                     new Insets(4, 30, 0, 0), 0, 0));
+
+    myMainPanel = new JPanel(new CardLayout());
+    myMainPanel.add(new JPanel(), EMPTY_PANEL_ID);
+    myMainPanel.add(panel, DATA_PANEL_ID);
+    return myMainPanel;
+  }
+
+  private void updateContext(final String qName) {
+    ApplicationManager.getApplication().runReadAction(new Runnable() {
+      public void run() {
+        final Project project = myProject;
+        final PsiClass psiClass = project != null ? DebuggerUtils.findClass(qName, project, GlobalSearchScope.allScope(project)) : null;
+        myLabelEditor.setContext(psiClass);
+        myChildrenEditor.setContext(psiClass);
+        myChildrenExpandedEditor.setContext(psiClass);
+        myListChildrenEditor.setContext(psiClass);
+      }
+    });
+  }
+
+  private void updateEnabledState() {
+    myLabelEditor.setEnabled(myRbExpressionLabel.isSelected());
+
+    final boolean isChildrenExpression = myRbExpressionChildrenRenderer.isSelected();
+    myChildrenExpandedEditor.setEnabled(isChildrenExpression);
+    myExpandedLabel.setEnabled(isChildrenExpression);
+    myChildrenEditor.setEnabled(isChildrenExpression);
+    myTable.setEnabled(myRbListChildrenRenderer.isSelected());
+  }
+
+  private JComponent createChildrenListEditor() {
+    final MyTableModel tableModel = new MyTableModel();
+    myTable = new JBTable(tableModel);
+    myListChildrenEditor = new DebuggerExpressionTextField(myProject, null, "NamedChildrenConfigurable");
+
+    final TableColumn exprColumn = myTable.getColumnModel().getColumn(EXPRESSION_TABLE_COLUMN);
+    exprColumn.setCellEditor(new AbstractTableCellEditor() {
+      public Object getCellEditorValue() {
+        return myListChildrenEditor.getText();
+      }
+
+      public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
+        myListChildrenEditor.setText((TextWithImports)value);
+        return myListChildrenEditor;
+      }
+    });
+    exprColumn.setCellRenderer(new DefaultTableCellRenderer() {
+      public Component getTableCellRendererComponent(JTable table,
+                                                     Object value,
+                                                     boolean isSelected,
+                                                     boolean hasFocus,
+                                                     int row,
+                                                     int column) {
+        final TextWithImports textWithImports = (TextWithImports)value;
+        final String text = (textWithImports != null) ? textWithImports.getText() : "";
+        return super.getTableCellRendererComponent(table, text, isSelected, hasFocus, row, column);
+      }
+    });
+
+    return ToolbarDecorator.createDecorator(myTable)
+      .setAddAction(new AnActionButtonRunnable() {
+        @Override
+        public void run(AnActionButton button) {
+          tableModel.addRow("", DebuggerUtils.getInstance().createExpressionWithImports(""));
+        }
+      }).setRemoveAction(new AnActionButtonRunnable() {
+        @Override
+        public void run(AnActionButton button) {
+          int selectedRow = myTable.getSelectedRow();
+          if (selectedRow >= 0 && selectedRow < myTable.getRowCount()) {
+            getTableModel().removeRow(selectedRow);
+          }
+        }
+      }).setMoveUpAction(new AnActionButtonRunnable() {
+        @Override
+        public void run(AnActionButton button) {
+          TableUtil.moveSelectedItemsUp(myTable);
+        }
+      }).setMoveDownAction(new AnActionButtonRunnable() {
+        @Override
+        public void run(AnActionButton button) {
+          TableUtil.moveSelectedItemsDown(myTable);
+        }
+      }).createPanel();
+  }
+
+  public boolean isModified() {
+    if (myRenderer == null) {
+      return false;
+    }
+    final CompoundReferenceRenderer cloned = (CompoundReferenceRenderer)myRenderer.clone();
+    flushDataTo(cloned);
+    return !DebuggerUtilsEx.externalizableEqual(cloned, myOriginalRenderer);
+  }
+
+  public void apply() throws ConfigurationException {
+    if (myRenderer == null) {
+      return;
+    }
+    flushDataTo(myRenderer);
+    // update the renderer to compare with in order to find out whether we've been modified since last apply
+    myOriginalRenderer = (CompoundReferenceRenderer)myRenderer.clone();
+  }
+
+  private void flushDataTo(final CompoundReferenceRenderer renderer) { // label
+    LabelRenderer labelRenderer = null;
+    if (myRbExpressionLabel.isSelected()) {
+      labelRenderer = new LabelRenderer();
+      labelRenderer.setLabelExpression(myLabelEditor.getText());
+    }
+    renderer.setLabelRenderer(labelRenderer);
+    // children
+    ChildrenRenderer childrenRenderer = null;
+    if (myRbExpressionChildrenRenderer.isSelected()) {
+      childrenRenderer = new ExpressionChildrenRenderer();
+      ((ExpressionChildrenRenderer)childrenRenderer).setChildrenExpression(myChildrenEditor.getText());
+      ((ExpressionChildrenRenderer)childrenRenderer).setChildrenExpandable(myChildrenExpandedEditor.getText());
+    }
+    else if (myRbListChildrenRenderer.isSelected()) {
+      childrenRenderer = new EnumerationChildrenRenderer(getTableModel().getExpressions());
+    }
+    renderer.setChildrenRenderer(childrenRenderer);
+    // classname
+    renderer.setClassName(myClassNameField.getText());
+  }
+
+  public void reset() {
+    final TextWithImports emptyExpressionFragment = new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, "");
+    ((CardLayout)myMainPanel.getLayout()).show(myMainPanel, myRenderer == null ? EMPTY_PANEL_ID : DATA_PANEL_ID);
+    if (myRenderer == null) {
+      return;
+    }
+    final String className = myRenderer.getClassName();
+    myClassNameField.setText(className);
+    final ValueLabelRenderer labelRenderer = myRenderer.getLabelRenderer();
+    final ChildrenRenderer childrenRenderer = myRenderer.getChildrenRenderer();
+    final NodeRendererSettings rendererSettings = NodeRendererSettings.getInstance();
+
+    if (rendererSettings.isBase(labelRenderer)) {
+      myRbDefaultLabel.setSelected(true);
+      myLabelEditor.setText(emptyExpressionFragment);
+    }
+    else {
+      myRbExpressionLabel.setSelected(true);
+      myLabelEditor.setText(((LabelRenderer)labelRenderer).getLabelExpression());
+    }
+
+    if (rendererSettings.isBase(childrenRenderer)) {
+      myRbDefaultChildrenRenderer.setSelected(true);
+      myChildrenEditor.setText(emptyExpressionFragment);
+      myChildrenExpandedEditor.setText(emptyExpressionFragment);
+      getTableModel().clear();
+    }
+    else if (childrenRenderer instanceof ExpressionChildrenRenderer) {
+      myRbExpressionChildrenRenderer.setSelected(true);
+      final ExpressionChildrenRenderer exprRenderer = (ExpressionChildrenRenderer)childrenRenderer;
+      myChildrenEditor.setText(exprRenderer.getChildrenExpression());
+      myChildrenExpandedEditor.setText(exprRenderer.getChildrenExpandable());
+      getTableModel().clear();
+    }
+    else {
+      myRbListChildrenRenderer.setSelected(true);
+      myChildrenEditor.setText(emptyExpressionFragment);
+      myChildrenExpandedEditor.setText(emptyExpressionFragment);
+      if (childrenRenderer instanceof EnumerationChildrenRenderer) {
+        getTableModel().init(((EnumerationChildrenRenderer)childrenRenderer).getChildren());
+      }
+      else {
+        getTableModel().clear();
+      }
+    }
+
+    updateEnabledState();
+    updateContext(className);
+  }
+
+  public void disposeUIResources() {
+    myRenderer = null;
+    myOriginalRenderer = null;
+    myLabelEditor.dispose();
+    myChildrenEditor.dispose();
+    myChildrenExpandedEditor.dispose();
+    myListChildrenEditor.dispose();
+    myLabelEditor = null;
+    myChildrenEditor = null;
+    myChildrenExpandedEditor = null;
+    myListChildrenEditor = null;
+    myProject = null;
+  }
+
+  private MyTableModel getTableModel() {
+    return (MyTableModel)myTable.getModel();
+  }
+
+  private final class MyTableModel extends AbstractTableModel {
+    private final List<Row> myData = new ArrayList<Row>();
+
+    public MyTableModel() {
+    }
+
+    public void init(List<Pair<String, TextWithImports>> data) {
+      myData.clear();
+      for (final Pair<String, TextWithImports> pair : data) {
+        myData.add(new Row(pair.getFirst(), pair.getSecond()));
+      }
+    }
+
+    public int getColumnCount() {
+      return 2;
+    }
+
+    public int getRowCount() {
+      return myData.size();
+    }
+
+    public boolean isCellEditable(int rowIndex, int columnIndex) {
+      return true;
+    }
+
+    public Class getColumnClass(int columnIndex) {
+      switch (columnIndex) {
+        case NAME_TABLE_COLUMN:
+          return String.class;
+        case EXPRESSION_TABLE_COLUMN:
+          return TextWithImports.class;
+        default:
+          return super.getColumnClass(columnIndex);
+      }
+    }
+
+    public Object getValueAt(int rowIndex, int columnIndex) {
+      if (rowIndex >= getRowCount()) {
+        return null;
+      }
+      final Row row = myData.get(rowIndex);
+      switch (columnIndex) {
+        case NAME_TABLE_COLUMN:
+          return row.name;
+        case EXPRESSION_TABLE_COLUMN:
+          return row.value;
+        default:
+          return null;
+      }
+    }
+
+    public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
+      if (rowIndex >= getRowCount()) {
+        return;
+      }
+      final Row row = myData.get(rowIndex);
+      switch (columnIndex) {
+        case NAME_TABLE_COLUMN:
+          row.name = (String)aValue;
+          break;
+        case EXPRESSION_TABLE_COLUMN:
+          row.value = (TextWithImports)aValue;
+          break;
+      }
+    }
+
+    public String getColumnName(int columnIndex) {
+      switch (columnIndex) {
+        case NAME_TABLE_COLUMN:
+          return DebuggerBundle.message("label.compound.renderer.configurable.table.header.name");
+        case EXPRESSION_TABLE_COLUMN:
+          return DebuggerBundle.message("label.compound.renderer.configurable.table.header.expression");
+        default:
+          return "";
+      }
+    }
+
+    public void addRow(final String name, final TextWithImports expressionWithImports) {
+      myData.add(new Row(name, expressionWithImports));
+      final int lastRow = myData.size() - 1;
+      fireTableRowsInserted(lastRow, lastRow);
+    }
+
+    public void removeRow(final int row) {
+      if (row >= 0 && row < myData.size()) {
+        myData.remove(row);
+        fireTableRowsDeleted(row, row);
+      }
+    }
+
+    public void clear() {
+      myData.clear();
+      fireTableDataChanged();
+    }
+
+    public List<Pair<String, TextWithImports>> getExpressions() {
+      final ArrayList<Pair<String, TextWithImports>> pairs = new ArrayList<Pair<String, TextWithImports>>(myData.size());
+      for (final Row row : myData) {
+        pairs.add(new Pair<String, TextWithImports>(row.name, row.value));
+      }
+      return pairs;
+    }
+
+    private final class Row {
+      public String name;
+      public TextWithImports value;
+
+      public Row(final String name, final TextWithImports value) {
+        this.name = name;
+        this.value = value;
+      }
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/DataBinding.java b/java/debugger/impl/src/com/intellij/debugger/settings/DataBinding.java
new file mode 100644
index 0000000..56de43c
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/settings/DataBinding.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2000-2009 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.debugger.settings;
+
+/**
+ * @author Eugene Zhuravlev
+ * Date: Apr 12, 2005
+ */
+public interface DataBinding {
+  void loadData(Object from);
+  void saveData(Object to);
+  boolean isModified(Object obj);
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerDataViewsConfigurable.java b/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerDataViewsConfigurable.java
new file mode 100644
index 0000000..c1207a5
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerDataViewsConfigurable.java
@@ -0,0 +1,340 @@
+/*
+ * Copyright 2000-2009 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.debugger.settings;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.ui.JavaDebuggerSupport;
+import com.intellij.debugger.ui.tree.render.ClassRenderer;
+import com.intellij.debugger.ui.tree.render.ToStringRenderer;
+import com.intellij.openapi.options.SearchableConfigurable;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.registry.Registry;
+import com.intellij.openapi.util.registry.ui.RegistryCheckBox;
+import com.intellij.ui.IdeBorderFactory;
+import com.intellij.ui.StateRestoringCheckBox;
+import com.intellij.ui.classFilter.ClassFilterEditor;
+import com.intellij.util.ui.UIUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import java.awt.*;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+
+/**
+ * @author Eugene Belyaev
+ */
+public class DebuggerDataViewsConfigurable implements SearchableConfigurable {
+  private JCheckBox myCbAutoscroll;
+  private JCheckBox myCbShowSyntheticFields;
+  private StateRestoringCheckBox myCbShowValFieldsAsLocalVariables;
+  private JCheckBox myCbSort;
+  private JCheckBox myCbHideNullArrayElements;
+  private JCheckBox myCbShowStatic;
+  private JCheckBox myCbShowDeclaredType;
+  private JCheckBox myCbShowFQNames;
+  private JCheckBox myCbShowObjectId;
+
+  private StateRestoringCheckBox myCbShowStaticFinalFields;
+  private final ArrayRendererConfigurable myArrayRendererConfigurable;
+  private JCheckBox myCbEnableAutoExpressions;
+  private JCheckBox myCbEnableAlternateViews;
+
+  private JCheckBox myCbEnableToString;
+  private JRadioButton myRbAllThatOverride;
+  private JRadioButton myRbFromList;
+  private ClassFilterEditor myToStringFilterEditor;
+  private JTextField myValueTooltipDelayField;
+  
+  private Project myProject;
+  private RegistryCheckBox myAutoTooltip;
+
+  public DebuggerDataViewsConfigurable(@Nullable Project project) {
+    myProject = project;
+    myArrayRendererConfigurable = new ArrayRendererConfigurable(NodeRendererSettings.getInstance().getArrayRenderer());
+  }
+
+  public void disposeUIResources() {
+    myArrayRendererConfigurable.disposeUIResources();
+    myToStringFilterEditor = null;
+    myProject = null;
+  }
+
+  public String getDisplayName() {
+    return DebuggerBundle.message("base.renderer.configurable.display.name");
+  }
+
+  public JComponent createComponent() {
+    if (myProject == null) {
+      myProject = JavaDebuggerSupport.getCurrentProject();
+    }
+    final JPanel panel = new JPanel(new GridBagLayout());
+
+    myCbAutoscroll = new JCheckBox(DebuggerBundle.message("label.base.renderer.configurable.autoscroll"));
+    myCbShowSyntheticFields = new JCheckBox(DebuggerBundle.message("label.base.renderer.configurable.show.synthetic.fields"));
+    myCbShowValFieldsAsLocalVariables = new StateRestoringCheckBox(DebuggerBundle.message("label.base.renderer.configurable.show.val.fields.as.locals"));
+    myCbSort = new JCheckBox(DebuggerBundle.message("label.base.renderer.configurable.sort.alphabetically"));
+    myCbHideNullArrayElements = new JCheckBox(DebuggerBundle.message("label.base.renderer.configurable.hide.null.array.elements"));
+    myCbShowStatic = new JCheckBox(DebuggerBundle.message("label.base.renderer.configurable.show.static.fields"));
+    myCbShowStaticFinalFields = new StateRestoringCheckBox(DebuggerBundle.message("label.base.renderer.configurable.show.static.final.fields"));
+    myCbEnableAlternateViews = new JCheckBox(DebuggerBundle.message("label.base.renderer.configurable.alternate.view"));
+    myCbEnableAutoExpressions = new JCheckBox(DebuggerBundle.message("label.base.renderer.configurable.auto.expressions"));
+    myCbShowStatic.addChangeListener(new ChangeListener(){
+      public void stateChanged(ChangeEvent e) {
+        if(myCbShowStatic.isSelected()) {
+          myCbShowStaticFinalFields.makeSelectable();
+        }
+        else {
+          myCbShowStaticFinalFields.makeUnselectable(false);
+        }
+      }
+    });
+    myCbShowSyntheticFields.addChangeListener(new ChangeListener() {
+      @Override
+      public void stateChanged(ChangeEvent e) {
+        if(myCbShowSyntheticFields.isSelected()) {
+          myCbShowValFieldsAsLocalVariables.makeSelectable();
+        }
+        else {
+          myCbShowValFieldsAsLocalVariables.makeUnselectable(false);
+        }
+      }
+    });
+    myCbShowDeclaredType = new JCheckBox(DebuggerBundle.message("label.base.renderer.configurable.show.declared.type"));
+    myCbShowFQNames = new JCheckBox(DebuggerBundle.message("label.base.renderer.configurable.show.fq.names"));
+    myCbShowObjectId = new JCheckBox(DebuggerBundle.message("label.base.renderer.configurable.show.object.id"));
+
+    myCbEnableToString = new JCheckBox(DebuggerBundle.message("label.base.renderer.configurable.enable.tostring"));
+    myRbAllThatOverride = new JRadioButton(DebuggerBundle.message("label.base.renderer.configurable.all.overridding"));
+    myRbFromList = new JRadioButton(DebuggerBundle.message("label.base.renderer.configurable.classes.from.list"));
+    ButtonGroup group = new ButtonGroup();
+    group.add(myRbAllThatOverride);
+    group.add(myRbFromList);
+    myToStringFilterEditor = new ClassFilterEditor(myProject, null, "reference.viewBreakpoints.classFilters.newPattern");
+    myCbEnableToString.addItemListener(new ItemListener() {
+      public void itemStateChanged(ItemEvent e) {
+        final boolean enabled = myCbEnableToString.isSelected();
+        myRbAllThatOverride.setEnabled(enabled);
+        myRbFromList.setEnabled(enabled);
+        myToStringFilterEditor.setEnabled(enabled && myRbFromList.isSelected());
+      }
+    });
+    myRbFromList.addItemListener(new ItemListener() {
+      public void itemStateChanged(ItemEvent e) {
+        myToStringFilterEditor.setEnabled(myCbEnableToString.isSelected() && myRbFromList.isSelected());
+      }
+    });
+
+    panel.add(myCbSort, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
+    panel.add(myCbAutoscroll, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(4, 0, 0, 0), 0, 0));
+
+
+    myAutoTooltip = new RegistryCheckBox(Registry.get("debugger.valueTooltipAutoShow"),
+                                         DebuggerBundle.message("label.base.renderer.configurable.autoTooltip"),
+                                         DebuggerBundle.message("label.base.renderer.configurable.autoTooltip.description",
+                                                                Registry.stringValue("ide.forcedShowTooltip")));
+    panel.add(myAutoTooltip, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(4, 0, 0, 0), 0, 0));
+
+    final JLabel tooltipLabel = new JLabel(DebuggerBundle.message("label.debugger.general.configurable.tooltips.delay"));
+    panel.add(tooltipLabel, new GridBagConstraints(1, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(4, 0, 0, 0), 0, 0));
+    myValueTooltipDelayField = new JTextField(10);
+    myValueTooltipDelayField.setMinimumSize(new Dimension(50, myValueTooltipDelayField.getPreferredSize().height));
+    panel.add(myValueTooltipDelayField, new GridBagConstraints(2, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(4, 0, 0, 0), 0, 0));
+    tooltipLabel.setLabelFor(myValueTooltipDelayField);
+
+    final JPanel showPanel = new JPanel(new GridBagLayout());
+    showPanel.setBorder(IdeBorderFactory.createTitledBorder("Show", true));
+
+    showPanel.add(myCbShowDeclaredType, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
+    showPanel.add(myCbShowObjectId, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(4, 0, 0, 0), 0, 0));
+    showPanel.add(myCbShowSyntheticFields, new GridBagConstraints(1, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 10, 0, 0), 0, 0));
+    showPanel.add(myCbShowStatic, new GridBagConstraints(1, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(4, 10, 0, 0), 0, 0));
+    showPanel.add(myCbShowValFieldsAsLocalVariables, new GridBagConstraints(2, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(4, 10, 0, 0), 0, 0));
+    showPanel.add(myCbShowStaticFinalFields, new GridBagConstraints(2, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(4, 10, 0, 0), 0, 0));
+    showPanel.add(myCbShowFQNames, new GridBagConstraints(3, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 10, 0, 0), 0, 0));
+
+    panel.add(showPanel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 3, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(4, 0, 0, 0), 0, 0));
+
+    final JPanel arraysPanel = new JPanel(new BorderLayout(0, UIUtil.DEFAULT_VGAP));
+    final JComponent arraysComponent = myArrayRendererConfigurable.createComponent();
+    arraysPanel.add(arraysComponent, BorderLayout.CENTER);
+    arraysPanel.add(myCbHideNullArrayElements, BorderLayout.SOUTH);
+    arraysPanel.setBorder(IdeBorderFactory.createTitledBorder("Arrays", true));
+    panel.add(arraysPanel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 3, 1, 1.0, 0.0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
+
+    panel.add(myCbEnableAutoExpressions, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 10), 0, 0));
+    panel.add(myCbEnableAlternateViews, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(4, 0, 0, 10), 0, 0));
+    // starting 4-th row
+    panel.add(myCbEnableToString, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 3, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(4, 0, 0, 0), 0, 0));
+    panel.add(myRbAllThatOverride, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 3, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 12, 0, 0), 0, 0));
+    panel.add(myRbFromList, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 3, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 12, 0, 0), 0, 0));
+    panel.add(myToStringFilterEditor, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 3, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 12, 0, 0), 0, 0));
+
+    return panel;
+  }
+
+  public void apply() {
+    final ViewsGeneralSettings generalSettings = ViewsGeneralSettings.getInstance();
+    final NodeRendererSettings rendererSettings = NodeRendererSettings.getInstance();
+
+    try {
+      DebuggerSettings.getInstance().VALUE_LOOKUP_DELAY = Integer.parseInt(myValueTooltipDelayField.getText().trim());
+    }
+    catch (NumberFormatException ignored) {
+    }
+    generalSettings.AUTOSCROLL_TO_NEW_LOCALS  = myCbAutoscroll.isSelected();
+    rendererSettings.setAlternateCollectionViewsEnabled(myCbEnableAlternateViews.isSelected());
+    generalSettings.HIDE_NULL_ARRAY_ELEMENTS  = myCbHideNullArrayElements.isSelected();
+    generalSettings.ENABLE_AUTO_EXPRESSIONS  = myCbEnableAutoExpressions.isSelected();
+
+    final ClassRenderer classRenderer = rendererSettings.getClassRenderer();
+    classRenderer.SORT_ASCENDING = myCbSort.isSelected();
+    classRenderer.SHOW_STATIC = myCbShowStatic.isSelected();
+    classRenderer.SHOW_STATIC_FINAL = myCbShowStaticFinalFields.isSelectedWhenSelectable();
+    classRenderer.SHOW_SYNTHETICS = myCbShowSyntheticFields.isSelected();
+    classRenderer.SHOW_VAL_FIELDS_AS_LOCAL_VARIABLES = myCbShowValFieldsAsLocalVariables.isSelectedWhenSelectable();
+    classRenderer.SHOW_DECLARED_TYPE = myCbShowDeclaredType.isSelected();
+    classRenderer.SHOW_FQ_TYPE_NAMES = myCbShowFQNames.isSelected();
+    classRenderer.SHOW_OBJECT_ID = myCbShowObjectId.isSelected();
+
+    final ToStringRenderer toStringRenderer = rendererSettings.getToStringRenderer();
+    toStringRenderer.setEnabled(myCbEnableToString.isSelected());
+    toStringRenderer.setUseClassFilters(myRbFromList.isSelected());
+    toStringRenderer.setClassFilters(myToStringFilterEditor.getFilters());
+
+    myAutoTooltip.save();
+
+    myArrayRendererConfigurable.apply();
+
+    rendererSettings.fireRenderersChanged();
+  }
+
+  public void reset() {
+    final ViewsGeneralSettings generalSettings = ViewsGeneralSettings.getInstance();
+    final NodeRendererSettings rendererSettings = NodeRendererSettings.getInstance();
+
+    myValueTooltipDelayField.setText(Integer.toString(DebuggerSettings.getInstance().VALUE_LOOKUP_DELAY));
+    myCbAutoscroll.setSelected(generalSettings.AUTOSCROLL_TO_NEW_LOCALS);
+    myCbHideNullArrayElements.setSelected(generalSettings.HIDE_NULL_ARRAY_ELEMENTS);
+    myCbEnableAlternateViews.setSelected(rendererSettings.areAlternateCollectionViewsEnabled());
+    myCbEnableAutoExpressions.setSelected(generalSettings.ENABLE_AUTO_EXPRESSIONS);
+
+    ClassRenderer classRenderer = rendererSettings.getClassRenderer();
+
+    myCbShowSyntheticFields.setSelected(classRenderer.SHOW_SYNTHETICS);
+    myCbShowValFieldsAsLocalVariables.setSelected(classRenderer.SHOW_VAL_FIELDS_AS_LOCAL_VARIABLES);
+    if (!classRenderer.SHOW_SYNTHETICS) {
+      myCbShowValFieldsAsLocalVariables.makeUnselectable(false);
+    }
+    myCbSort.setSelected(classRenderer.SORT_ASCENDING);
+    myCbShowStatic.setSelected(classRenderer.SHOW_STATIC);
+    myCbShowStaticFinalFields.setSelected(classRenderer.SHOW_STATIC_FINAL);
+    if(!classRenderer.SHOW_STATIC) {
+      myCbShowStaticFinalFields.makeUnselectable(false);
+    }
+    myCbShowDeclaredType.setSelected(classRenderer.SHOW_DECLARED_TYPE);
+    myCbShowFQNames.setSelected(classRenderer.SHOW_FQ_TYPE_NAMES);
+    myCbShowObjectId.setSelected(classRenderer.SHOW_OBJECT_ID);
+
+    final ToStringRenderer toStringRenderer = rendererSettings.getToStringRenderer();
+    final boolean toStringEnabled = toStringRenderer.isEnabled();
+    final boolean useClassFilters = toStringRenderer.isUseClassFilters();
+    myCbEnableToString.setSelected(toStringEnabled);
+    myRbAllThatOverride.setSelected(!useClassFilters);
+    myRbFromList.setSelected(useClassFilters);
+    myToStringFilterEditor.setFilters(toStringRenderer.getClassFilters());
+    myToStringFilterEditor.setEnabled(toStringEnabled && useClassFilters);
+    myRbFromList.setEnabled(toStringEnabled);
+    myRbAllThatOverride.setEnabled(toStringEnabled);
+
+    myArrayRendererConfigurable.reset();
+  }
+
+  public boolean isModified() {
+    return areGeneralSettingsModified() || areDefaultRenderersModified() || areDebuggerSettingsModified();
+  }
+
+  private boolean areDebuggerSettingsModified() {
+    try {
+      return DebuggerSettings.getInstance().VALUE_LOOKUP_DELAY != Integer.parseInt(myValueTooltipDelayField.getText().trim());
+    }
+    catch (NumberFormatException ignored) {
+    }
+    return false;
+  }
+
+  private boolean areGeneralSettingsModified() {
+    ViewsGeneralSettings generalSettings = ViewsGeneralSettings.getInstance();
+    return
+    (generalSettings.AUTOSCROLL_TO_NEW_LOCALS  != myCbAutoscroll.isSelected()) ||
+    (generalSettings.ENABLE_AUTO_EXPRESSIONS  != myCbEnableAutoExpressions.isSelected()) ||
+    (generalSettings.HIDE_NULL_ARRAY_ELEMENTS  != myCbHideNullArrayElements.isSelected()) || myAutoTooltip.isChanged();
+  }
+
+  private boolean areDefaultRenderersModified() {
+    if (myArrayRendererConfigurable.isModified()) {
+      return true;
+    }
+    final NodeRendererSettings rendererSettings = NodeRendererSettings.getInstance();
+
+    final ClassRenderer classRenderer = rendererSettings.getClassRenderer();
+    final boolean isClassRendererModified=
+    (classRenderer.SORT_ASCENDING != myCbSort.isSelected()) ||
+    (classRenderer.SHOW_STATIC != myCbShowStatic.isSelected()) ||
+    (classRenderer.SHOW_STATIC_FINAL != myCbShowStaticFinalFields.isSelectedWhenSelectable()) ||
+    (classRenderer.SHOW_SYNTHETICS != myCbShowSyntheticFields.isSelected()) ||
+    (classRenderer.SHOW_VAL_FIELDS_AS_LOCAL_VARIABLES != myCbShowValFieldsAsLocalVariables.isSelectedWhenSelectable()) ||
+    (classRenderer.SHOW_DECLARED_TYPE != myCbShowDeclaredType.isSelected()) ||
+    (classRenderer.SHOW_FQ_TYPE_NAMES != myCbShowFQNames.isSelected()) ||
+    (classRenderer.SHOW_OBJECT_ID != myCbShowObjectId.isSelected());
+    if (isClassRendererModified) {
+      return true;
+    }
+
+    final ToStringRenderer toStringRenderer = rendererSettings.getToStringRenderer();
+    final boolean isToStringRendererModified =
+      (toStringRenderer.isEnabled() != myCbEnableToString.isSelected()) ||
+      (toStringRenderer.isUseClassFilters() != myRbFromList.isSelected()) ||
+      (!DebuggerUtilsEx.filterEquals(toStringRenderer.getClassFilters(), myToStringFilterEditor.getFilters()));
+    if (isToStringRendererModified) {
+      return true;
+    }
+
+    if (rendererSettings.areAlternateCollectionViewsEnabled() != myCbEnableAlternateViews.isSelected()) {
+      return true;
+    }
+
+    return false;
+  }
+
+  @NotNull
+  public String getHelpTopic() {
+    return "reference.idesettings.debugger.dataviews";
+  }
+
+  @NotNull
+  public String getId() {
+    return getHelpTopic();
+  }
+
+  public Runnable enableSearch(String option) {
+    return null;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerHotswapConfigurable.java b/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerHotswapConfigurable.java
new file mode 100644
index 0000000..a70be30
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerHotswapConfigurable.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2000-2009 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.debugger.settings;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.openapi.options.SearchableConfigurable;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import javax.swing.border.Border;
+import java.awt.*;
+
+public class DebuggerHotswapConfigurable implements SearchableConfigurable {
+  private JCheckBox myHotswapInBackground;
+  private JCheckBox myCbCompileBeforeHotswap;
+  private JCheckBox myCbHangWarningEnabled;
+  private JRadioButton myRbAlways;
+  private JRadioButton myRbNever;
+  private JRadioButton myRbAsk;
+
+  public void reset() {
+    final DebuggerSettings settings = DebuggerSettings.getInstance();
+    myHotswapInBackground.setSelected(settings.HOTSWAP_IN_BACKGROUND);
+    myCbCompileBeforeHotswap.setSelected(settings.COMPILE_BEFORE_HOTSWAP);
+    myCbHangWarningEnabled.setSelected(settings.HOTSWAP_HANG_WARNING_ENABLED);
+
+    if(DebuggerSettings.RUN_HOTSWAP_ALWAYS.equals(settings.RUN_HOTSWAP_AFTER_COMPILE)) {
+      myRbAlways.setSelected(true);
+    }
+    else if(DebuggerSettings.RUN_HOTSWAP_NEVER.equals(settings.RUN_HOTSWAP_AFTER_COMPILE)) {
+      myRbNever.setSelected(true);
+    }
+    else {
+      myRbAsk.setSelected(true);
+    }
+  }
+
+  public void apply() {
+    getSettingsTo(DebuggerSettings.getInstance());
+  }
+
+  private void getSettingsTo(DebuggerSettings settings) {
+    settings.HOTSWAP_IN_BACKGROUND = myHotswapInBackground.isSelected();
+    settings.COMPILE_BEFORE_HOTSWAP = myCbCompileBeforeHotswap.isSelected();
+    settings.HOTSWAP_HANG_WARNING_ENABLED = myCbHangWarningEnabled.isSelected();
+
+    if (myRbAlways.isSelected()) {
+      settings.RUN_HOTSWAP_AFTER_COMPILE = DebuggerSettings.RUN_HOTSWAP_ALWAYS;
+    }
+    else if (myRbNever.isSelected()) {
+      settings.RUN_HOTSWAP_AFTER_COMPILE = DebuggerSettings.RUN_HOTSWAP_NEVER;
+    }
+    else {
+      settings.RUN_HOTSWAP_AFTER_COMPILE = DebuggerSettings.RUN_HOTSWAP_ASK;
+    }
+  }
+
+  public boolean isModified() {
+    final DebuggerSettings currentSettings = DebuggerSettings.getInstance();
+    final DebuggerSettings debuggerSettings = currentSettings.clone();
+    getSettingsTo(debuggerSettings);
+    return !debuggerSettings.equals(currentSettings);
+  }
+
+  public String getDisplayName() {
+    return DebuggerBundle.message("debugger.hotswap.configurable.display.name");
+  }
+
+  public String getHelpTopic() {
+    return "reference.idesettings.debugger.hotswap";
+  }
+
+  @NotNull
+  public String getId() {
+    return getHelpTopic();
+  }
+
+  public Runnable enableSearch(String option) {
+    return null;
+  }
+
+  public JComponent createComponent() {
+    final JPanel panel = new JPanel(new GridBagLayout());
+
+    myCbCompileBeforeHotswap = new JCheckBox(DebuggerBundle.message("label.debugger.hotswap.configurable.compile.before.hotswap"));
+    myCbHangWarningEnabled = new JCheckBox(DebuggerBundle.message("label.debugger.hotswap.configurable.enable.vm.hang.warning"));
+    myHotswapInBackground = new JCheckBox(DebuggerBundle.message("label.debugger.hotswap.configurable.hotswap.background"));
+    myRbAlways = new JRadioButton(DebuggerBundle.message("label.debugger.hotswap.configurable.always"));
+    myRbNever = new JRadioButton(DebuggerBundle.message("label.debugger.hotswap.configurable.never"));
+    myRbAsk = new JRadioButton(DebuggerBundle.message("label.debugger.hotswap.configurable.ask"));
+
+    panel.add(myCbCompileBeforeHotswap, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
+    panel.add(myCbHangWarningEnabled, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(4, 0, 0, 0), 0, 0));
+    panel.add(myHotswapInBackground, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(4, 0, 0, 0), 0, 0));
+    
+    int cbLeftOffset = 0;
+    final Border border = myCbCompileBeforeHotswap.getBorder();
+    if (border != null) {
+      final Insets insets = border.getBorderInsets(myCbCompileBeforeHotswap);
+      if (insets != null) {
+        cbLeftOffset = insets.left;
+      }
+    }
+
+    final ButtonGroup group = new ButtonGroup();
+    group.add(myRbAlways);
+    group.add(myRbNever);
+    group.add(myRbAsk);
+    final Box box = Box.createHorizontalBox();
+    box.add(myRbAlways);
+    box.add(myRbNever);
+    box.add(myRbAsk);
+    final JPanel reloadPanel = new JPanel(new BorderLayout());
+    reloadPanel.add(box, BorderLayout.CENTER);
+    reloadPanel.add(new JLabel(DebuggerBundle.message("label.debugger.hotswap.configurable.reload.classes")), BorderLayout.WEST);
+    panel.add(reloadPanel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(4, cbLeftOffset, 0, 0), 0, 0));
+
+    return panel;
+  }
+
+
+  public void disposeUIResources() {
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerLaunchingConfigurable.java b/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerLaunchingConfigurable.java
new file mode 100644
index 0000000..f731c89
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerLaunchingConfigurable.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2000-2009 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.debugger.settings;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.openapi.options.Configurable;
+import com.intellij.openapi.util.SystemInfo;
+import com.intellij.openapi.util.registry.Registry;
+import com.intellij.ui.StateRestoringCheckBox;
+import com.intellij.ui.components.panels.VerticalBox;
+
+import javax.swing.*;
+import javax.swing.border.Border;
+import java.awt.*;
+
+public class DebuggerLaunchingConfigurable implements Configurable{
+  private JRadioButton myRbSocket;
+  private JRadioButton myRbShmem;
+  private JCheckBox myHideDebuggerCheckBox;
+  private StateRestoringCheckBox myCbForceClassicVM;
+  private JCheckBox myCbDisableJIT;
+  private JCheckBox myFocusAppCheckBox;
+
+  public void reset() {
+    final DebuggerSettings settings = DebuggerSettings.getInstance();
+    if (!SystemInfo.isWindows) {
+      myRbSocket.setSelected(true);
+      myRbShmem.setEnabled(false);
+    }
+    else {
+      if (settings.DEBUGGER_TRANSPORT == DebuggerSettings.SHMEM_TRANSPORT) {
+        myRbShmem.setSelected(true);
+      }
+      else {
+        myRbSocket.setSelected(true);
+      }
+      myRbShmem.setEnabled(true);
+    }
+    myHideDebuggerCheckBox.setSelected(settings.HIDE_DEBUGGER_ON_PROCESS_TERMINATION);
+    myCbForceClassicVM.setSelected(settings.FORCE_CLASSIC_VM);
+    myCbDisableJIT.setSelected(settings.DISABLE_JIT);
+    myFocusAppCheckBox.setSelected(Registry.is("debugger.mayBringFrameToFrontOnBreakpoint"));
+  }
+
+  public void apply() {
+    getSettingsTo(DebuggerSettings.getInstance());
+  }
+
+  private void getSettingsTo(DebuggerSettings settings) {
+    if (myRbShmem.isSelected()) {
+      settings.DEBUGGER_TRANSPORT = DebuggerSettings.SHMEM_TRANSPORT;
+    }
+    else {
+      settings.DEBUGGER_TRANSPORT = DebuggerSettings.SOCKET_TRANSPORT;
+    }
+    settings.HIDE_DEBUGGER_ON_PROCESS_TERMINATION = myHideDebuggerCheckBox.isSelected();
+    settings.FORCE_CLASSIC_VM = myCbForceClassicVM.isSelectedWhenSelectable();
+    settings.DISABLE_JIT = myCbDisableJIT.isSelected();
+    Registry.get("debugger.mayBringFrameToFrontOnBreakpoint").setValue(myFocusAppCheckBox.isSelected());
+  }
+
+  public boolean isModified() {
+    final DebuggerSettings currentSettings = DebuggerSettings.getInstance();
+    final DebuggerSettings debuggerSettings = currentSettings.clone();
+    getSettingsTo(debuggerSettings);
+    return !debuggerSettings.equals(currentSettings) || Registry.is("debugger.mayBringFrameToFrontOnBreakpoint") != myFocusAppCheckBox.isSelected();
+  }
+
+  public String getDisplayName() {
+    return DebuggerBundle.message("debugger.launching.configurable.display.name");
+  }
+
+  public String getHelpTopic() {
+    return "reference.idesettings.debugger.launching";
+  }
+
+  public JComponent createComponent() {
+    myCbForceClassicVM = new StateRestoringCheckBox(DebuggerBundle.message("label.debugger.launching.configurable.force.classic.vm"));
+    myCbDisableJIT = new JCheckBox(DebuggerBundle.message("label.debugger.launching.configurable.disable.jit"));
+    myHideDebuggerCheckBox = new JCheckBox(DebuggerBundle.message("label.debugger.launching.configurable.hide.window"));
+    myRbSocket = new JRadioButton(DebuggerBundle.message("label.debugger.launching.configurable.socket"));
+    myRbShmem = new JRadioButton(DebuggerBundle.message("label.debugger.launching.configurable.shmem"));
+    myFocusAppCheckBox = new JCheckBox(DebuggerBundle.message("label.debugger.focusAppOnBreakpoint"));
+
+    int cbLeftOffset = 0;
+    final Border border = myCbForceClassicVM.getBorder();
+    if (border != null) {
+      final Insets insets = border.getBorderInsets(myCbForceClassicVM);
+      if (insets != null) {
+        cbLeftOffset = insets.left;
+      }
+    }
+
+    final ButtonGroup gr = new ButtonGroup();
+    gr.add(myRbSocket);
+    gr.add(myRbShmem);
+    final Box box = Box.createHorizontalBox();
+    box.add(myRbSocket);
+    box.add(myRbShmem);
+    final JPanel transportPanel = new JPanel(new BorderLayout());
+    transportPanel.add(new JLabel(DebuggerBundle.message("label.debugger.launching.configurable.debugger.transport")), BorderLayout.WEST);
+    transportPanel.add(box, BorderLayout.CENTER);
+
+    VerticalBox panel = new VerticalBox();
+    panel.setOpaque(false);
+    panel.add(transportPanel);
+    panel.add(myCbForceClassicVM);
+    panel.add(myCbDisableJIT);
+    panel.add(myHideDebuggerCheckBox);
+    panel.add(myFocusAppCheckBox);
+
+    JPanel result = new JPanel(new BorderLayout());
+    result.add(panel, BorderLayout.NORTH);
+
+    return result;
+  }
+
+
+  public void disposeUIResources() {
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerSettings.java b/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerSettings.java
new file mode 100644
index 0000000..274fff6
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerSettings.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright 2000-2009 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.debugger.settings;
+
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.openapi.components.NamedComponent;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.DefaultJDOMExternalizer;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.JDOMExternalizable;
+import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.ui.classFilter.ClassFilter;
+import org.jdom.Element;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class DebuggerSettings implements JDOMExternalizable, NamedComponent, Cloneable {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.settings.DebuggerSettings");
+  public static final int SOCKET_TRANSPORT = 0;
+  public static final int SHMEM_TRANSPORT = 1;
+
+  @NonNls public static final String SUSPEND_ALL = "SuspendAll";
+  @NonNls public static final String SUSPEND_THREAD = "SuspendThread";
+  @NonNls public static final String SUSPEND_NONE = "SuspendNone";
+
+  @NonNls public static final String EVALUATE_FRAGMENT = "EvaluateFragment";
+  @NonNls public static final String EVALUATE_EXPRESSION = "EvaluateExpression";
+
+  @NonNls public static final String RUN_HOTSWAP_ALWAYS = "RunHotswapAlways";
+  @NonNls public static final String RUN_HOTSWAP_NEVER = "RunHotswapNever";
+  @NonNls public static final String RUN_HOTSWAP_ASK = "RunHotswapAsk";
+
+  public boolean TRACING_FILTERS_ENABLED;
+  public int VALUE_LOOKUP_DELAY; // ms
+  public int DEBUGGER_TRANSPORT;
+  public boolean FORCE_CLASSIC_VM;
+  public boolean DISABLE_JIT;
+  public boolean HIDE_DEBUGGER_ON_PROCESS_TERMINATION;
+  public boolean HOTSWAP_IN_BACKGROUND = true;
+  public boolean SKIP_SYNTHETIC_METHODS;
+  public boolean SKIP_CONSTRUCTORS;
+  public boolean SKIP_GETTERS;
+  public boolean SKIP_CLASSLOADERS;
+
+  public String EVALUATION_DIALOG_TYPE;
+  public String RUN_HOTSWAP_AFTER_COMPILE;
+  public boolean COMPILE_BEFORE_HOTSWAP;
+  public boolean HOTSWAP_HANG_WARNING_ENABLED = true;
+
+  public volatile boolean WATCH_RETURN_VALUES = false;
+  public volatile boolean AUTO_VARIABLES_MODE = false;
+  public volatile boolean SHOW_LIBRARY_STACKFRAMES = true;
+
+
+  private ClassFilter[] mySteppingFilters = ClassFilter.EMPTY_ARRAY;
+
+  private Map<String, ContentState> myContentStates = new HashMap<String, ContentState>();
+
+  public ClassFilter[] getSteppingFilters() {
+    final ClassFilter[] rv = new ClassFilter[mySteppingFilters.length];
+    for (int idx = 0; idx < rv.length; idx++) {
+      rv[idx] = mySteppingFilters[idx].clone();
+    }
+    return rv;
+  }
+
+  void setSteppingFilters(ClassFilter[] steppingFilters) {
+    mySteppingFilters = steppingFilters != null ? steppingFilters : ClassFilter.EMPTY_ARRAY;
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  public void readExternal(Element parentNode) throws InvalidDataException {
+    DefaultJDOMExternalizer.readExternal(this, parentNode);
+    List<ClassFilter> filtersList = new ArrayList<ClassFilter>();
+
+    for (final Object o : parentNode.getChildren("filter")) {
+      Element filter = (Element)o;
+      filtersList.add(DebuggerUtilsEx.create(filter));
+    }
+    setSteppingFilters(filtersList.toArray(new ClassFilter[filtersList.size()]));
+
+    filtersList.clear();
+
+    final List contents = parentNode.getChildren("content");
+    myContentStates.clear();
+    for (Object content : contents) {
+      final ContentState state = new ContentState((Element)content);
+      myContentStates.put(state.getType(), state);
+    }
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  public void writeExternal(Element parentNode) throws WriteExternalException {
+    DefaultJDOMExternalizer.writeExternal(this, parentNode);
+    for (ClassFilter mySteppingFilter : mySteppingFilters) {
+      Element element = new Element("filter");
+      parentNode.addContent(element);
+      mySteppingFilter.writeExternal(element);
+    }
+
+    for (ContentState eachState : myContentStates.values()) {
+      final Element content = new Element("content");
+      if (eachState.write(content)) {
+        parentNode.addContent(content);
+      }
+    }
+  }
+
+  public static DebuggerSettings getInstance() {
+    return ServiceManager.getService(DebuggerSettings.class);
+  }
+
+  public boolean equals(Object obj) {
+    if (!(obj instanceof DebuggerSettings)) return false;
+    DebuggerSettings secondSettings = (DebuggerSettings)obj;
+
+    return
+      TRACING_FILTERS_ENABLED == secondSettings.TRACING_FILTERS_ENABLED &&
+      VALUE_LOOKUP_DELAY == secondSettings.VALUE_LOOKUP_DELAY &&
+      DEBUGGER_TRANSPORT == secondSettings.DEBUGGER_TRANSPORT &&
+      FORCE_CLASSIC_VM == secondSettings.FORCE_CLASSIC_VM &&
+      DISABLE_JIT == secondSettings.DISABLE_JIT &&
+      HIDE_DEBUGGER_ON_PROCESS_TERMINATION == secondSettings.HIDE_DEBUGGER_ON_PROCESS_TERMINATION &&
+      HOTSWAP_IN_BACKGROUND == secondSettings.HOTSWAP_IN_BACKGROUND &&
+      SKIP_SYNTHETIC_METHODS == secondSettings.SKIP_SYNTHETIC_METHODS &&
+      SKIP_CLASSLOADERS == secondSettings.SKIP_CLASSLOADERS &&
+      SKIP_CONSTRUCTORS == secondSettings.SKIP_CONSTRUCTORS &&
+      SKIP_GETTERS == secondSettings.SKIP_GETTERS &&
+      COMPILE_BEFORE_HOTSWAP == secondSettings.COMPILE_BEFORE_HOTSWAP &&
+      HOTSWAP_HANG_WARNING_ENABLED == secondSettings.HOTSWAP_HANG_WARNING_ENABLED &&
+      (RUN_HOTSWAP_AFTER_COMPILE != null ? RUN_HOTSWAP_AFTER_COMPILE.equals(secondSettings.RUN_HOTSWAP_AFTER_COMPILE) : secondSettings.RUN_HOTSWAP_AFTER_COMPILE == null) &&
+      DebuggerUtilsEx.filterEquals(mySteppingFilters, secondSettings.mySteppingFilters);
+  }
+
+  public DebuggerSettings clone() {
+    try {
+      final DebuggerSettings cloned = (DebuggerSettings)super.clone();
+      cloned.myContentStates = new HashMap<String, ContentState>();
+      for (Map.Entry<String, ContentState> entry : myContentStates.entrySet()) {
+        cloned.myContentStates.put(entry.getKey(), entry.getValue().clone());
+      }
+      cloned.mySteppingFilters = new ClassFilter[mySteppingFilters.length];
+      for (int idx = 0; idx < mySteppingFilters.length; idx++) {
+        cloned.mySteppingFilters[idx] = mySteppingFilters[idx].clone();
+      }
+      return cloned;
+    }
+    catch (CloneNotSupportedException e) {
+      LOG.error(e);
+    }
+    return null;
+  }
+
+  @NotNull
+  public String getComponentName() {
+    return "DebuggerSettings";
+  }
+
+  public static class ContentState implements Cloneable {
+
+    private final String myType;
+    private boolean myMinimized;
+    private String mySelectedTab;
+    private double mySplitProportion;
+    private boolean myDetached;
+    private boolean myHorizontalToolbar;
+    private boolean myMaximized;
+
+    public ContentState(final String type) {
+      myType = type;
+    }
+
+    public ContentState(Element element) {
+      myType = element.getAttributeValue("type");
+      myMinimized = "true".equalsIgnoreCase(element.getAttributeValue("minimized"));
+      myMaximized = "true".equalsIgnoreCase(element.getAttributeValue("maximized"));
+      mySelectedTab = element.getAttributeValue("selected");
+      final String split = element.getAttributeValue("split");
+      if (split != null) {
+        mySplitProportion = Double.valueOf(split);
+      }
+      myDetached = "true".equalsIgnoreCase(element.getAttributeValue("detached"));
+      myHorizontalToolbar = !"false".equalsIgnoreCase(element.getAttributeValue("horizontal"));
+    }
+
+    public boolean write(final Element element) {
+      element.setAttribute("type", myType);
+      element.setAttribute("minimized", Boolean.valueOf(myMinimized).toString());
+      element.setAttribute("maximized", Boolean.valueOf(myMaximized).toString());
+      if (mySelectedTab != null) {
+        element.setAttribute("selected", mySelectedTab);
+      }
+      element.setAttribute("split", new Double(mySplitProportion).toString());
+      element.setAttribute("detached", Boolean.valueOf(myDetached).toString());
+      element.setAttribute("horizontal", Boolean.valueOf(myHorizontalToolbar).toString());
+      return true;
+    }
+
+    public String getType() {
+      return myType;
+    }
+
+    public String getSelectedTab() {
+      return mySelectedTab;
+    }
+
+    public boolean isMinimized() {
+      return myMinimized;
+    }
+
+    public void setMinimized(final boolean minimized) {
+      myMinimized = minimized;
+    }
+
+    public void setMaximized(final boolean maximized) {
+      myMaximized = maximized;
+    }
+
+    public boolean isMaximized() {
+      return myMaximized;
+    }
+
+    public void setSelectedTab(final String selectedTab) {
+      mySelectedTab = selectedTab;
+    }
+
+    public void setSplitProportion(double splitProportion) {
+      mySplitProportion = splitProportion;
+    }
+
+    public double getSplitProportion(double defaultValue) {
+      return mySplitProportion <= 0 || mySplitProportion >= 1 ? defaultValue : mySplitProportion;
+    }
+
+    public void setDetached(final boolean detached) {
+      myDetached = detached;
+    }
+
+    public boolean isDetached() {
+      return myDetached;
+    }
+
+    public boolean isHorizontalToolbar() {
+      return myHorizontalToolbar;
+    }
+
+    public void setHorizontalToolbar(final boolean horizontalToolbar) {
+      myHorizontalToolbar = horizontalToolbar;
+    }
+
+    public ContentState clone() throws CloneNotSupportedException {
+      return (ContentState)super.clone();
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerSteppingConfigurable.java b/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerSteppingConfigurable.java
new file mode 100644
index 0000000..d85e636
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerSteppingConfigurable.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2000-2009 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.debugger.settings;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.ui.JavaDebuggerSupport;
+import com.intellij.openapi.options.Configurable;
+import com.intellij.openapi.options.SearchableConfigurable;
+import com.intellij.openapi.project.Project;
+import com.intellij.ui.classFilter.ClassFilterEditor;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+public class DebuggerSteppingConfigurable implements SearchableConfigurable, Configurable.NoScroll {
+  private JCheckBox myCbStepInfoFiltersEnabled;
+  private JCheckBox myCbSkipSyntheticMethods;
+  private JCheckBox myCbSkipConstructors;
+  private JCheckBox myCbSkipClassLoaders;
+  private ClassFilterEditor mySteppingFilterEditor;
+  private JCheckBox myCbSkipSimpleGetters;
+  private Project myProject;
+
+  public void reset() {
+    final DebuggerSettings settings = DebuggerSettings.getInstance();
+    myCbSkipSimpleGetters.setSelected(settings.SKIP_GETTERS);
+    myCbSkipSyntheticMethods.setSelected(settings.SKIP_SYNTHETIC_METHODS);
+    myCbSkipConstructors.setSelected(settings.SKIP_CONSTRUCTORS);
+    myCbSkipClassLoaders.setSelected(settings.SKIP_CLASSLOADERS);
+
+    myCbStepInfoFiltersEnabled.setSelected(settings.TRACING_FILTERS_ENABLED);
+
+    mySteppingFilterEditor.setFilters(settings.getSteppingFilters());
+    mySteppingFilterEditor.setEnabled(settings.TRACING_FILTERS_ENABLED);
+
+
+  }
+
+  public void apply() {
+    getSettingsTo(DebuggerSettings.getInstance());
+  }
+
+  private void getSettingsTo(DebuggerSettings settings) {
+    settings.SKIP_GETTERS = myCbSkipSimpleGetters.isSelected();
+    settings.SKIP_SYNTHETIC_METHODS = myCbSkipSyntheticMethods.isSelected();
+    settings.SKIP_CONSTRUCTORS = myCbSkipConstructors.isSelected();
+    settings.SKIP_CLASSLOADERS = myCbSkipClassLoaders.isSelected();
+    settings.TRACING_FILTERS_ENABLED = myCbStepInfoFiltersEnabled.isSelected();
+
+    mySteppingFilterEditor.stopEditing();
+    settings.setSteppingFilters(mySteppingFilterEditor.getFilters());
+  }
+
+  public boolean isModified() {
+    final DebuggerSettings currentSettings = DebuggerSettings.getInstance();
+    final DebuggerSettings debuggerSettings = currentSettings.clone();
+    getSettingsTo(debuggerSettings);
+    return !debuggerSettings.equals(currentSettings);
+  }
+
+  public String getDisplayName() {
+    return DebuggerBundle.message("debugger.stepping.configurable.display.name");
+  }
+
+  @NotNull
+  public String getHelpTopic() {
+    return "reference.idesettings.debugger.stepping";
+  }
+
+  @NotNull
+  public String getId() {
+    return getHelpTopic();
+  }
+
+  public Runnable enableSearch(String option) {
+    return null;
+  }
+
+  public JComponent createComponent() {
+    final JPanel panel = new JPanel(new GridBagLayout());
+    myProject = JavaDebuggerSupport.getCurrentProject();
+    myCbSkipSyntheticMethods = new JCheckBox(DebuggerBundle.message("label.debugger.general.configurable.skip.synthetic.methods"));
+    myCbSkipConstructors = new JCheckBox(DebuggerBundle.message("label.debugger.general.configurable.skip.constructors"));
+    myCbSkipClassLoaders = new JCheckBox(DebuggerBundle.message("label.debugger.general.configurable.skip.classloaders"));
+    myCbSkipSimpleGetters = new JCheckBox(DebuggerBundle.message("label.debugger.general.configurable.skip.simple.getters"));
+    myCbStepInfoFiltersEnabled = new JCheckBox(DebuggerBundle.message("label.debugger.general.configurable.step.filters.list.header"));
+    panel.add(myCbSkipSyntheticMethods, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0),0, 0));
+    panel.add(myCbSkipConstructors, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0),0, 0));
+    panel.add(myCbSkipClassLoaders, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0),0, 0));
+    panel.add(myCbSkipSimpleGetters, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0),0, 0));
+    panel.add(myCbStepInfoFiltersEnabled, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(8, 0, 0, 0),0, 0));
+
+    mySteppingFilterEditor = new ClassFilterEditor(myProject, null, "reference.viewBreakpoints.classFilters.newPattern");
+    panel.add(mySteppingFilterEditor, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 5, 0, 0),0, 0));
+
+    myCbStepInfoFiltersEnabled.addActionListener(new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        mySteppingFilterEditor.setEnabled(myCbStepInfoFiltersEnabled.isSelected());
+      }
+    });
+    return panel;
+  }
+
+  public void disposeUIResources() {
+    mySteppingFilterEditor = null;
+    myProject = null;
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/FieldDataBinding.java b/java/debugger/impl/src/com/intellij/debugger/settings/FieldDataBinding.java
new file mode 100644
index 0000000..8473fbf
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/settings/FieldDataBinding.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2000-2009 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.debugger.settings;
+
+import org.jetbrains.annotations.NonNls;
+
+import java.lang.reflect.Field;
+
+import com.intellij.debugger.DebuggerBundle;
+
+/**
+ * @author Eugene Zhuravlev
+ * Date: Apr 12, 2005
+ */
+public abstract class FieldDataBinding implements DataBinding{
+
+  private final String myFieldName;
+
+  protected FieldDataBinding(@NonNls String fieldName) {
+    myFieldName = fieldName;
+  }
+
+  public final void loadData(Object from) {
+    try {
+      final Field field = findField(from);
+      doLoadData(from, field);
+    }
+    catch (IllegalAccessException e) {
+      throw new RuntimeException(e.getMessage(), e);
+    }
+  }
+
+
+  public final void saveData(Object to) {
+    try {
+      final Field field = findField(to);
+      doSaveData(to, field);
+    }
+    catch (IllegalAccessException e) {
+      throw new RuntimeException(e.getMessage(), e);
+    }
+  }
+
+  public boolean isModified(Object obj) {
+    try {
+      final Field field = findField(obj);
+      return isModified(obj, field);
+    }
+    catch (IllegalAccessException e) {
+      throw new RuntimeException(e.getMessage(), e);
+    }
+  }
+
+  protected abstract void doLoadData(Object from, Field field) throws IllegalAccessException;
+
+  protected abstract void doSaveData(Object to, Field field) throws IllegalAccessException;
+
+  protected abstract boolean isModified(Object obj, Field field) throws IllegalAccessException;
+
+  private Field findField(Object from) {
+    final Class objectClass = Object.class;
+    for (Class aClass = from.getClass(); !aClass.equals(objectClass); aClass = aClass.getSuperclass()) {
+      try {
+        final Field field = aClass.getDeclaredField(myFieldName);
+        field.setAccessible(true);
+        return field;
+      }
+      catch (NoSuchFieldException e) {
+        // ignored, just continue
+      }
+    }
+    throw new RuntimeException(DebuggerBundle.message("error.field.not.found.in.class", myFieldName, from.getClass().getName()));
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/NodeRendererSettings.java b/java/debugger/impl/src/com/intellij/debugger/settings/NodeRendererSettings.java
new file mode 100644
index 0000000..d64c783
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/settings/NodeRendererSettings.java
@@ -0,0 +1,546 @@
+/*
+ * Copyright 2000-2012 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.debugger.settings;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.engine.DebugProcess;
+import com.intellij.debugger.engine.evaluation.*;
+import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl;
+import com.intellij.debugger.ui.impl.watch.WatchItemDescriptor;
+import com.intellij.debugger.ui.tree.ValueDescriptor;
+import com.intellij.debugger.ui.tree.render.*;
+import com.intellij.debugger.ui.tree.render.Renderer;
+import com.intellij.openapi.components.*;
+import com.intellij.openapi.fileTypes.StdFileTypes;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.*;
+import com.intellij.psi.CommonClassNames;
+import com.intellij.util.EventDispatcher;
+import com.intellij.util.containers.InternalIterator;
+import com.intellij.util.ui.ColorIcon;
+import com.sun.jdi.*;
+import org.jdom.Element;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * User: lex
+ * Date: Sep 18, 2003
+ * Time: 8:00:25 PM
+ */
+@State(
+  name="NodeRendererSettings",
+  storages= {
+    @Storage(
+      file = StoragePathMacros.APP_CONFIG + "/debugger.renderers.xml"
+    )}
+)
+public class NodeRendererSettings implements PersistentStateComponent<Element> {
+  @NonNls private static final String REFERENCE_RENDERER = "Reference renderer";
+  @NonNls public static final String RENDERER_TAG = "Renderer";
+  @NonNls private static final String RENDERER_ID = "ID";
+
+  private final EventDispatcher<NodeRendererSettingsListener> myDispatcher = EventDispatcher.create(NodeRendererSettingsListener.class);
+  private final List<NodeRenderer> myPluginRenderers = new ArrayList<NodeRenderer>();
+  private RendererConfiguration myCustomRenderers = new RendererConfiguration(this);
+
+  // base renderers
+  private final PrimitiveRenderer myPrimitiveRenderer = new PrimitiveRenderer();
+  private final ArrayRenderer myArrayRenderer = new ArrayRenderer();
+  private final ClassRenderer myClassRenderer = new ClassRenderer();
+  private final HexRenderer myHexRenderer = new HexRenderer();
+  private final ToStringRenderer myToStringRenderer = new ToStringRenderer();
+  private final CompoundReferenceRenderer myColorRenderer;
+  // alternate collections
+  private final NodeRenderer[] myAlternateCollectionRenderers = new NodeRenderer[]{
+    createCompoundReferenceRenderer(
+      "Map", CommonClassNames.JAVA_UTIL_MAP,
+      createLabelRenderer(" size = ", "size()", null),
+      createExpressionChildrenRenderer("entrySet().toArray()", "!isEmpty()")
+    ),
+    createCompoundReferenceRenderer(
+      "Map.Entry", "java.util.Map$Entry",
+      new MapEntryLabelRenderer()/*createLabelRenderer(null, "\" \" + getKey() + \" -> \" + getValue()", null)*/,
+      createEnumerationChildrenRenderer(new String[][]{{"key", "getKey()"}, {"value", "getValue()"}})
+    ),
+    createCompoundReferenceRenderer(
+      "Collection", "java.util.Collection",
+      createLabelRenderer(" size = ", "size()", null),
+      createExpressionChildrenRenderer("toArray()", "!isEmpty()")
+    )
+  };
+  @NonNls private static final String HEX_VIEW_ENABLED = "HEX_VIEW_ENABLED";
+  @NonNls private static final String ALTERNATIVE_COLLECTION_VIEW_ENABLED = "ALTERNATIVE_COLLECTION_VIEW_ENABLED";
+  @NonNls private static final String CUSTOM_RENDERERS_TAG_NAME = "CustomRenderers";
+  
+  public NodeRendererSettings() {
+    myColorRenderer = new ColorObjectRenderer(this);
+    // default configuration
+    myHexRenderer.setEnabled(false);
+    myToStringRenderer.setEnabled(true);
+    setAlternateCollectionViewsEnabled(true);
+    myColorRenderer.setEnabled(true);
+  }
+  
+  public static NodeRendererSettings getInstance() {
+    return ServiceManager.getService(NodeRendererSettings.class);
+  }
+  
+  public void addPluginRenderer(NodeRenderer renderer) {
+    myPluginRenderers.add(renderer);
+  }
+
+  public void removePluginRenderer(NodeRenderer renderer) {
+    myPluginRenderers.remove(renderer);
+  }
+  
+  public void setAlternateCollectionViewsEnabled(boolean enabled) {
+    for (NodeRenderer myAlternateCollectionRenderer : myAlternateCollectionRenderers) {
+      myAlternateCollectionRenderer.setEnabled(enabled);
+    }
+  }
+
+  public boolean areAlternateCollectionViewsEnabled() {
+    return myAlternateCollectionRenderers[0].isEnabled();
+  }
+
+  public boolean equals(Object o) {
+    if(!(o instanceof NodeRendererSettings)) return false;
+
+    return DebuggerUtilsEx.elementsEqual(getState(), ((NodeRendererSettings)o).getState());
+  }
+
+  public void addListener(NodeRendererSettingsListener listener) {
+    myDispatcher.addListener(listener);
+  }
+
+  public void removeListener(NodeRendererSettingsListener listener) {
+    myDispatcher.removeListener(listener);
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  public Element getState()  {
+    final Element element = new Element("NodeRendererSettings");
+    JDOMExternalizerUtil.writeField(element, HEX_VIEW_ENABLED, myHexRenderer.isEnabled()? "true" : "false");
+    JDOMExternalizerUtil.writeField(element, ALTERNATIVE_COLLECTION_VIEW_ENABLED, areAlternateCollectionViewsEnabled()? "true" : "false");
+    try {
+      element.addContent(writeRenderer(myArrayRenderer));
+      element.addContent(writeRenderer(myToStringRenderer));
+      element.addContent(writeRenderer(myClassRenderer));
+      if (myCustomRenderers.getRendererCount() > 0) {
+        final Element custom = new Element(CUSTOM_RENDERERS_TAG_NAME);
+        element.addContent(custom);
+        myCustomRenderers.writeExternal(custom);
+      }
+    }
+    catch (WriteExternalException e) {
+      // ignore
+    }
+    return element;
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  public void loadState(final Element root) {
+    final String hexEnabled = JDOMExternalizerUtil.readField(root, HEX_VIEW_ENABLED);
+    if (hexEnabled != null) {
+      myHexRenderer.setEnabled("true".equalsIgnoreCase(hexEnabled));
+    }
+
+    final String alternativeEnabled = JDOMExternalizerUtil.readField(root, ALTERNATIVE_COLLECTION_VIEW_ENABLED);
+    if (alternativeEnabled != null) {
+      setAlternateCollectionViewsEnabled("true".equalsIgnoreCase(alternativeEnabled));
+    }
+
+    final List rendererElements = root.getChildren(RENDERER_TAG);
+    for (final Object rendererElement : rendererElements) {
+      final Element elem = (Element)rendererElement;
+      final String id = elem.getAttributeValue(RENDERER_ID);
+      if (id == null) {
+        continue;
+      }
+      try {
+        if (ArrayRenderer.UNIQUE_ID.equals(id)) {
+          myArrayRenderer.readExternal(elem);
+        }
+        else if (ToStringRenderer.UNIQUE_ID.equals(id)) {
+          myToStringRenderer.readExternal(elem);
+        }
+        else if (ClassRenderer.UNIQUE_ID.equals(id)) {
+          myClassRenderer.readExternal(elem);
+        }
+      }
+      catch (InvalidDataException e) {
+        // ignore
+      }
+    }
+    final Element custom = root.getChild(CUSTOM_RENDERERS_TAG_NAME);
+    if (custom != null) {
+      myCustomRenderers.readExternal(custom);
+    }
+
+    myDispatcher.getMulticaster().renderersChanged();
+  }
+
+  public RendererConfiguration getCustomRenderers() {
+    return myCustomRenderers;
+  }
+
+  public void setCustomRenderers(@NotNull final RendererConfiguration customRenderers) {
+    RendererConfiguration oldConfig = myCustomRenderers;
+    myCustomRenderers = customRenderers;
+    if (oldConfig == null || !oldConfig.equals(customRenderers)) {
+      fireRenderersChanged();
+    }
+  }
+
+  public List<NodeRenderer> getPluginRenderers() {
+    return new ArrayList<NodeRenderer>(myPluginRenderers);
+  }
+  
+  public PrimitiveRenderer getPrimitiveRenderer() {
+    return myPrimitiveRenderer;
+  }
+
+  public ArrayRenderer getArrayRenderer() {
+    return myArrayRenderer;
+  }
+
+  public ClassRenderer getClassRenderer() {
+    return myClassRenderer;
+  }
+
+  public HexRenderer getHexRenderer() {
+    return myHexRenderer;
+  }
+
+  public ToStringRenderer getToStringRenderer() {
+    return myToStringRenderer;
+  }
+
+  public NodeRenderer[] getAlternateCollectionRenderers() {
+    return myAlternateCollectionRenderers;
+  }
+
+  public void fireRenderersChanged() {
+    myDispatcher.getMulticaster().renderersChanged();
+  }
+
+  public List<NodeRenderer> getAllRenderers() {
+    // the order is important as the renderers are applied according to it
+    final List<NodeRenderer> allRenderers = new ArrayList<NodeRenderer>();
+    allRenderers.add(myHexRenderer);
+    allRenderers.add(myPrimitiveRenderer);
+    allRenderers.addAll(myPluginRenderers);
+    myCustomRenderers.iterateRenderers(new InternalIterator<NodeRenderer>() {
+      public boolean visit(final NodeRenderer renderer) {
+        allRenderers.add(renderer);
+        return true;
+      }
+    });
+    for (NodeRenderer myAlternateCollectionRenderer : myAlternateCollectionRenderers) {
+      allRenderers.add(myAlternateCollectionRenderer);
+    }
+    allRenderers.add(myColorRenderer);
+    allRenderers.add(myToStringRenderer);
+    allRenderers.add(myArrayRenderer);
+    allRenderers.add(myClassRenderer);
+    return allRenderers;
+  }
+
+  public boolean isBase(final Renderer renderer) {
+    return renderer == myPrimitiveRenderer || renderer == myArrayRenderer || renderer == myClassRenderer;
+  }
+
+  public Renderer readRenderer(Element root) throws InvalidDataException {
+    if (root == null) {
+      return null;
+    }
+
+    if (!RENDERER_TAG.equals(root.getName())) {
+      throw new InvalidDataException("Cannot read renderer - tag name is not '" + RENDERER_TAG + "'");
+    }
+
+    final String rendererId = root.getAttributeValue(RENDERER_ID);
+    if(rendererId == null) {
+      throw new InvalidDataException("unknown renderer ID: " + rendererId);
+    }
+
+    final Renderer renderer = createRenderer(rendererId);
+    if(renderer == null) {
+      throw new InvalidDataException("unknown renderer ID: " + rendererId);
+    }
+
+    renderer.readExternal(root);
+
+    return renderer;
+  }
+
+  public Element writeRenderer(Renderer renderer) throws WriteExternalException {
+    Element root = new Element(RENDERER_TAG);
+    if(renderer != null) {
+      root.setAttribute(RENDERER_ID  , renderer.getUniqueId());
+      renderer.writeExternal(root);
+    }
+    return root;
+  }
+
+  public Renderer createRenderer(final String rendererId) {
+    if (ClassRenderer.UNIQUE_ID.equals(rendererId)) {
+      return myClassRenderer;
+    }
+    else if (ArrayRenderer.UNIQUE_ID.equals(rendererId)) {
+      return myArrayRenderer;
+    }
+    else if (PrimitiveRenderer.UNIQUE_ID.equals(rendererId)) {
+      return myPrimitiveRenderer;
+    }
+    else if(HexRenderer.UNIQUE_ID.equals(rendererId)) {
+      return myHexRenderer;
+    }
+    else if(rendererId.equals(ExpressionChildrenRenderer.UNIQUE_ID)) {
+      return new ExpressionChildrenRenderer();
+    }
+    else if(rendererId.equals(LabelRenderer.UNIQUE_ID)) {
+      return new LabelRenderer();
+    }
+    else if(rendererId.equals(EnumerationChildrenRenderer.UNIQUE_ID)) {
+      return new EnumerationChildrenRenderer();
+    }
+    else if(rendererId.equals(ToStringRenderer.UNIQUE_ID)) {
+      return myToStringRenderer;
+    }
+    else if(rendererId.equals(CompoundNodeRenderer.UNIQUE_ID) || rendererId.equals(REFERENCE_RENDERER)) {
+      return createCompoundReferenceRenderer("unnamed", CommonClassNames.JAVA_LANG_OBJECT, null, null);
+    }
+    return null;
+  }
+
+  private CompoundReferenceRenderer createCompoundReferenceRenderer(
+    @NonNls final String rendererName, @NonNls final String className, final ValueLabelRenderer labelRenderer, final ChildrenRenderer childrenRenderer
+    ) {
+    CompoundReferenceRenderer renderer = new CompoundReferenceRenderer(this, rendererName, labelRenderer, childrenRenderer);
+    renderer.setClassName(className);
+    return renderer;
+  }
+
+  private ExpressionChildrenRenderer createExpressionChildrenRenderer(@NonNls String expressionText, @NonNls String childrenExpandableText) {
+    final ExpressionChildrenRenderer childrenRenderer = new ExpressionChildrenRenderer();
+    childrenRenderer.setChildrenExpression(new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, expressionText, "", StdFileTypes.JAVA));
+    if (childrenExpandableText != null) {
+      childrenRenderer.setChildrenExpandable(new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, childrenExpandableText, "", StdFileTypes.JAVA));
+    }
+    return childrenRenderer;
+  }
+
+  private EnumerationChildrenRenderer createEnumerationChildrenRenderer(@NonNls String[][] expressions) {
+    final EnumerationChildrenRenderer childrenRenderer = new EnumerationChildrenRenderer();
+    if (expressions != null && expressions.length > 0) {
+      final ArrayList<Pair<String, TextWithImports>> childrenList = new ArrayList<Pair<String, TextWithImports>>(expressions.length);
+      for (final String[] expression : expressions) {
+        childrenList.add(new Pair<String, TextWithImports>(expression[0], new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, expression[1], "", StdFileTypes.JAVA)));
+      }
+      childrenRenderer.setChildren(childrenList);
+    }
+    return childrenRenderer;
+  }
+
+  private static LabelRenderer createLabelRenderer(@NonNls final String prefix, @NonNls final String expressionText, @NonNls final String postfix) {
+    final LabelRenderer labelRenderer = new LabelRenderer() {
+      public String calcLabel(ValueDescriptor descriptor, EvaluationContext evaluationContext, DescriptorLabelListener labelListener) throws EvaluateException {
+        final String evaluated = super.calcLabel(descriptor, evaluationContext, labelListener);
+        if (prefix == null && postfix == null) {
+          return evaluated;
+        }
+        if (prefix != null && postfix != null) {
+          return prefix + evaluated + postfix;
+        }
+        if (prefix != null) {
+          return prefix + evaluated;
+        }
+        return evaluated + postfix;
+      }
+    };
+    labelRenderer.setLabelExpression(new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, expressionText, "", StdFileTypes.JAVA));
+    return labelRenderer;
+  }
+
+  private static class MapEntryLabelRenderer extends ReferenceRenderer implements ValueLabelRenderer{
+    private static final Computable<String> NULL_LABEL_COMPUTABLE = new Computable<String>() {
+      public String compute() {
+        return "null";
+      }
+    };
+
+    private final MyCachedEvaluator myKeyExpression = new MyCachedEvaluator();
+    private final MyCachedEvaluator myValueExpression = new MyCachedEvaluator();
+
+    private MapEntryLabelRenderer() {
+      super("java.util.Map$Entry");
+      myKeyExpression.setReferenceExpression(new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, "this.getKey()", "", StdFileTypes.JAVA));
+      myValueExpression.setReferenceExpression(new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, "this.getValue()", "", StdFileTypes.JAVA));
+    }
+
+    public Icon calcValueIcon(ValueDescriptor descriptor, EvaluationContext evaluationContext, DescriptorLabelListener listener) throws EvaluateException {
+      return null;
+    }
+
+    public String calcLabel(ValueDescriptor descriptor, EvaluationContext evaluationContext, DescriptorLabelListener listener) throws EvaluateException {
+      final DescriptorUpdater descriptorUpdater = new DescriptorUpdater(descriptor, listener);
+
+      final Value originalValue = descriptor.getValue();
+      final Pair<Computable<String>, ValueDescriptorImpl> keyPair = createValueComputable(evaluationContext, originalValue, myKeyExpression, descriptorUpdater);
+      final Pair<Computable<String>, ValueDescriptorImpl> valuePair = createValueComputable(evaluationContext, originalValue, myValueExpression, descriptorUpdater);
+
+      descriptorUpdater.setKeyDescriptor(keyPair.second);
+      descriptorUpdater.setValueDescriptor(valuePair.second);
+
+      return DescriptorUpdater.constructLabelText(keyPair.first.compute(), valuePair.first.compute());
+    }
+
+    private Pair<Computable<String>, ValueDescriptorImpl> createValueComputable(final EvaluationContext evaluationContext,
+                                                                                Value originalValue,
+                                                                                final MyCachedEvaluator evaluator,
+                                                                                final DescriptorLabelListener listener) throws EvaluateException {
+      final Value eval = doEval(evaluationContext, originalValue, evaluator);
+      if (eval != null) {
+        final WatchItemDescriptor evalDescriptor = new WatchItemDescriptor(evaluationContext.getProject(), evaluator.getReferenceExpression(), eval);
+        evalDescriptor.setShowIdLabel(false);
+        return new Pair<Computable<String>, ValueDescriptorImpl>(new Computable<String>() {
+          public String compute() {
+            evalDescriptor.updateRepresentation((EvaluationContextImpl)evaluationContext, listener);
+            return evalDescriptor.getValueLabel();
+          }
+        }, evalDescriptor);
+      }
+      return new Pair<Computable<String>, ValueDescriptorImpl>(NULL_LABEL_COMPUTABLE, null);
+    }
+
+    public String getUniqueId() {
+      return "MapEntry renderer";
+    }
+
+    private Value doEval(EvaluationContext evaluationContext, Value originalValue, MyCachedEvaluator cachedEvaluator)
+      throws EvaluateException {
+      final DebugProcess debugProcess = evaluationContext.getDebugProcess();
+      if (originalValue == null) {
+        return null;
+      }
+      try {
+        final ExpressionEvaluator evaluator = cachedEvaluator.getEvaluator(debugProcess.getProject());
+        if(!debugProcess.isAttached()) {
+          throw EvaluateExceptionUtil.PROCESS_EXITED;
+        }
+        final EvaluationContext thisEvaluationContext = evaluationContext.createEvaluationContext(originalValue);
+        return evaluator.evaluate(thisEvaluationContext);
+      }
+      catch (final EvaluateException ex) {
+        throw new EvaluateException(DebuggerBundle.message("error.unable.to.evaluate.expression") + " " + ex.getMessage(), ex);
+      }
+    }
+
+    private class MyCachedEvaluator extends CachedEvaluator {
+      protected String getClassName() {
+        return MapEntryLabelRenderer.this.getClassName();
+      }
+
+      public ExpressionEvaluator getEvaluator(Project project) throws EvaluateException {
+        return super.getEvaluator(project);
+      }
+    }
+  }
+
+  private static class DescriptorUpdater implements DescriptorLabelListener {
+    private final ValueDescriptor myTargetDescriptor;
+    @Nullable
+    private ValueDescriptorImpl myKeyDescriptor;
+    @Nullable
+    private ValueDescriptorImpl myValueDescriptor;
+    private final DescriptorLabelListener myDelegate;
+
+    private DescriptorUpdater(ValueDescriptor descriptor, DescriptorLabelListener delegate) {
+      myTargetDescriptor = descriptor;
+      myDelegate = delegate;
+    }
+
+    public void setKeyDescriptor(@Nullable ValueDescriptorImpl keyDescriptor) {
+      myKeyDescriptor = keyDescriptor;
+    }
+
+    public void setValueDescriptor(@Nullable ValueDescriptorImpl valueDescriptor) {
+      myValueDescriptor = valueDescriptor;
+    }
+
+    public void labelChanged() {
+      myTargetDescriptor.setValueLabel(constructLabelText(getDescriptorLabel(myKeyDescriptor), getDescriptorLabel(myValueDescriptor)));
+      myDelegate.labelChanged();
+    }
+
+    static String constructLabelText(final String keylabel, final String valueLabel) {
+      return keylabel + " -> " + valueLabel;
+    }
+
+    private static String getDescriptorLabel(final ValueDescriptorImpl keyDescriptor) {
+      return keyDescriptor == null? "null" : keyDescriptor.getValueLabel();
+    }
+  }
+
+  private static class ColorObjectRenderer extends CompoundReferenceRenderer {
+
+    public ColorObjectRenderer(final NodeRendererSettings rendererSettings) {
+      super(rendererSettings, "Color", null, null);
+      setClassName("java.awt.Color");
+    }
+
+    public String calcLabel(ValueDescriptor descriptor, EvaluationContext evaluationContext, DescriptorLabelListener listener) throws EvaluateException {
+      final ToStringRenderer toStringRenderer = myRendererSettings.getToStringRenderer();
+      if (toStringRenderer.isEnabled() && DebuggerManagerEx.getInstanceEx(evaluationContext.getProject()).getContext().isEvaluationPossible()) {
+        return toStringRenderer.calcLabel(descriptor, evaluationContext, listener);
+      }
+      return super.calcLabel(descriptor, evaluationContext, listener);
+    }
+
+    public Icon calcValueIcon(ValueDescriptor descriptor, EvaluationContext evaluationContext, DescriptorLabelListener listener) throws EvaluateException {
+      final Value value = descriptor.getValue();
+      if (value instanceof ObjectReference) {
+        try {
+          final ObjectReference objRef = (ObjectReference)value;
+          final ReferenceType refType = objRef.referenceType();
+          final Field valueField = refType.fieldByName("value");
+          if (valueField != null) {
+            final Value rgbValue = objRef.getValue(valueField);
+            if (rgbValue instanceof IntegerValue) {
+              final Color color = new Color(((IntegerValue)rgbValue).value(), true);
+              return new ColorIcon(16, 12, color, true);
+            }
+          }
+        }
+        catch (Exception e) {
+          throw new EvaluateException(e.getMessage(), e);
+        }
+      }
+      return null;
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/RendererConfiguration.java b/java/debugger/impl/src/com/intellij/debugger/settings/RendererConfiguration.java
new file mode 100644
index 0000000..a3eef6a
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/settings/RendererConfiguration.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2000-2009 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.debugger.settings;
+
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.ui.tree.render.NodeRenderer;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.JDOMExternalizable;
+import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.util.containers.InternalIterator;
+import org.jdom.Element;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public class RendererConfiguration implements Cloneable, JDOMExternalizable {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.settings.NodeRendererSettings");
+
+  private static final int VERSION = 8;
+
+  private List<NodeRenderer> myRepresentationNodes = new ArrayList<NodeRenderer>();
+  private final NodeRendererSettings myRendererSettings;
+
+  protected RendererConfiguration(NodeRendererSettings rendererSettings) {
+    myRendererSettings = rendererSettings;
+  }
+
+  public RendererConfiguration clone() {
+    RendererConfiguration result = null;
+    try {
+      result = (RendererConfiguration)super.clone();
+    }
+    catch (CloneNotSupportedException e) {
+      LOG.error(e);
+    }
+    result.myRepresentationNodes = new ArrayList<NodeRenderer>();
+    for (Iterator<NodeRenderer> iterator = myRepresentationNodes.iterator(); iterator.hasNext();) {
+      result.addRenderer((NodeRenderer)iterator.next().clone());
+    }
+
+    return result;
+  }
+
+  public boolean equals(Object o) {
+    if(!(o instanceof RendererConfiguration)) return false;
+
+    return DebuggerUtilsEx.externalizableEqual(this, (RendererConfiguration)o);
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  public void writeExternal(final Element element) throws WriteExternalException {
+    for (Iterator<NodeRenderer> iterator = myRepresentationNodes.iterator(); iterator.hasNext();) {
+      NodeRenderer renderer = iterator.next();
+      element.addContent(myRendererSettings.writeRenderer(renderer));
+    }
+    element.setAttribute("VERSION", String.valueOf(VERSION));
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  public void readExternal(final Element root) {
+    String versionAttrib = root.getAttributeValue("VERSION");
+    int configurationVersion = -1;
+    if (versionAttrib != null) {
+      try {
+        configurationVersion = Integer.parseInt(versionAttrib);
+      }
+      catch (NumberFormatException e) {
+        configurationVersion = -1;
+      }
+    }
+    if(configurationVersion != VERSION) {
+      return;
+    }
+
+    List<Element> children = root.getChildren(NodeRendererSettings.RENDERER_TAG);
+
+    myRepresentationNodes.clear();
+    for (Element nodeElement : children) {
+      try {
+        addRenderer((NodeRenderer)myRendererSettings.readRenderer(nodeElement));
+      }
+      catch (Exception e) {
+        LOG.debug(e);
+      }
+    }
+  }
+
+  public void addRenderer(NodeRenderer renderer) {
+    myRepresentationNodes.add(renderer);
+  }
+
+  public void removeRenderer(NodeRenderer renderer) {
+    myRepresentationNodes.remove(renderer);
+  }
+
+  public void removeAllRenderers() {
+    myRepresentationNodes.clear();
+  }
+
+  public void iterateRenderers(InternalIterator<NodeRenderer> iterator) {
+    for (Iterator<NodeRenderer> it = myRepresentationNodes.iterator(); it.hasNext();) {
+      final NodeRenderer renderer = it.next();
+      final boolean shouldContinue = iterator.visit(renderer);
+      if (!shouldContinue) {
+        break;
+      }
+    }
+  }
+
+  public int getRendererCount() {
+    return myRepresentationNodes.size();
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/TextComponentBinding.java b/java/debugger/impl/src/com/intellij/debugger/settings/TextComponentBinding.java
new file mode 100644
index 0000000..773de1c
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/settings/TextComponentBinding.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2000-2009 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.debugger.settings;
+
+import org.jetbrains.annotations.NonNls;
+
+import javax.swing.text.JTextComponent;
+import java.lang.reflect.Field;
+
+/**
+ * @author Eugene Zhuravlev
+ * Date: Apr 12, 2005
+ */
+public class TextComponentBinding extends FieldDataBinding{
+  private final JTextComponent myTextComponent;
+
+  public TextComponentBinding(@NonNls String dataFieldName, JTextComponent textComponent) {
+    super(dataFieldName);
+    myTextComponent = textComponent;
+  }
+
+  public void doLoadData(Object from, Field field) throws IllegalAccessException {
+    final String value = (String)field.get(from);
+    myTextComponent.setText(value);
+  }
+
+  public void doSaveData(Object to, Field field) throws IllegalAccessException{
+    field.set(to, myTextComponent.getText().trim());
+  }
+
+  protected boolean isModified(Object obj, Field field) throws IllegalAccessException {
+    final String value = (String)field.get(obj);
+    return myTextComponent.getText().trim().equals(value);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/ThreadsViewConfigurable.form b/java/debugger/impl/src/com/intellij/debugger/settings/ThreadsViewConfigurable.form
new file mode 100644
index 0000000..2eb90d9
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/settings/ThreadsViewConfigurable.form
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.debugger.settings.ThreadsViewConfigurable">
+  <grid id="a2574" binding="myPanel" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+    <margin top="0" left="0" bottom="0" right="0"/>
+    <constraints>
+      <xy x="126" y="76" width="271" height="203"/>
+      <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3"/>
+    </constraints>
+    <properties/>
+    <border type="none"/>
+    <children>
+      <grid id="4cb6d" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="0">
+        <margin top="0" left="0" bottom="0" right="0"/>
+        <constraints>
+          <xy x="0" y="0" width="271" height="79"/>
+          <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="1" fill="1"/>
+        </constraints>
+        <properties/>
+        <border type="etched"/>
+        <children>
+          <component id="b8249" class="javax.swing.JCheckBox" binding="myShowGroupsCheckBox">
+            <constraints>
+              <xy x="2" y="2" width="140" height="27"/>
+              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0"/>
+            </constraints>
+            <properties>
+              <margin top="5" left="2" bottom="2" right="2"/>
+              <text resource-bundle="messages/DebuggerBundle" key="label.threads.view.configurable.show.thread.groups"/>
+            </properties>
+          </component>
+          <component id="5bfe" class="javax.swing.JCheckBox" binding="myShowSyntheticsCheckBox">
+            <constraints>
+              <xy x="2" y="29" width="267" height="24"/>
+              <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0"/>
+            </constraints>
+            <properties>
+              <text resource-bundle="messages/DebuggerBundle" key="label.threads.view.configurable.show.stack.frames.for.synthetic.methods"/>
+            </properties>
+          </component>
+          <component id="a7f8b" class="javax.swing.JCheckBox" binding="myShowCurrentThreadChechBox">
+            <constraints>
+              <xy x="2" y="53" width="206" height="24"/>
+              <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0"/>
+            </constraints>
+            <properties>
+              <text resource-bundle="messages/DebuggerBundle" key="label.threads.view.configurable.current.thread.on.top"/>
+            </properties>
+          </component>
+        </children>
+      </grid>
+      <grid id="f4cba" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="0">
+        <margin top="0" left="0" bottom="0" right="0"/>
+        <constraints>
+          <xy x="0" y="84" width="271" height="79"/>
+          <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="1" fill="1"/>
+        </constraints>
+        <properties/>
+        <border type="etched"/>
+        <children>
+          <component id="4f5e9" class="javax.swing.JCheckBox" binding="myLineNumberCheckBox">
+            <constraints>
+              <xy x="2" y="2" width="128" height="27"/>
+              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0"/>
+            </constraints>
+            <properties>
+              <margin top="5" left="2" bottom="2" right="2"/>
+              <text resource-bundle="messages/DebuggerBundle" key="label.threads.view.configurable.show.line.number"/>
+            </properties>
+          </component>
+          <component id="2fbc6" class="javax.swing.JCheckBox" binding="myClassNameCheckBox">
+            <constraints>
+              <xy x="2" y="29" width="123" height="24"/>
+              <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0"/>
+            </constraints>
+            <properties>
+              <text resource-bundle="messages/DebuggerBundle" key="label.threads.view.configurable.show.class.name"/>
+            </properties>
+          </component>
+          <component id="b56d7" class="javax.swing.JCheckBox" binding="mySourceCheckBox">
+            <constraints>
+              <xy x="2" y="53" width="156" height="24"/>
+              <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0"/>
+            </constraints>
+            <properties>
+              <text resource-bundle="messages/DebuggerBundle" key="label.threads.view.configurable.show.source.file.name"/>
+            </properties>
+          </component>
+        </children>
+      </grid>
+    </children>
+  </grid>
+</form>
diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/ThreadsViewConfigurable.java b/java/debugger/impl/src/com/intellij/debugger/settings/ThreadsViewConfigurable.java
new file mode 100644
index 0000000..1015542
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/settings/ThreadsViewConfigurable.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2000-2009 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.debugger.settings;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.openapi.options.BaseConfigurable;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.project.ProjectManager;
+
+import javax.swing.*;
+import java.util.Iterator;
+
+/**
+ * @author Eugene Belyaev
+ */
+public class ThreadsViewConfigurable extends BaseConfigurable {
+  private final ThreadsViewSettings mySettings;
+  private JPanel myPanel;
+  private JCheckBox myShowGroupsCheckBox;
+  private JCheckBox myLineNumberCheckBox;
+  private JCheckBox myClassNameCheckBox;
+  private JCheckBox mySourceCheckBox;
+  private JCheckBox myShowSyntheticsCheckBox;
+  private JCheckBox myShowCurrentThreadChechBox;
+  private final CompositeDataBinding myDataBinding = new CompositeDataBinding();
+
+  public ThreadsViewConfigurable(ThreadsViewSettings settings) {
+    mySettings = settings;
+
+    myDataBinding.addBinding(new ToggleButtonBinding("SHOW_CLASS_NAME", myClassNameCheckBox));
+    myDataBinding.addBinding(new ToggleButtonBinding("SHOW_LINE_NUMBER", myLineNumberCheckBox));
+    myDataBinding.addBinding(new ToggleButtonBinding("SHOW_SOURCE_NAME", mySourceCheckBox));
+    myDataBinding.addBinding(new ToggleButtonBinding("SHOW_THREAD_GROUPS", myShowGroupsCheckBox));
+    myDataBinding.addBinding(new ToggleButtonBinding("SHOW_SYNTHETIC_FRAMES", myShowSyntheticsCheckBox));
+    myDataBinding.addBinding(new ToggleButtonBinding("SHOW_CURRENT_THREAD", myShowCurrentThreadChechBox));
+  }
+
+  public String getDisplayName() {
+    return DebuggerBundle.message("threads.view.configurable.display.name");
+  }
+
+  public JComponent createComponent() {
+    return myPanel;
+  }
+
+  public void apply() {
+    myDataBinding.saveData(mySettings);
+    final Project[] openProjects = ProjectManager.getInstance().getOpenProjects();
+    for (int i = 0; i < openProjects.length; i++) {
+      Project project = openProjects[i];
+      for (Iterator iterator = (DebuggerManagerEx.getInstanceEx(project)).getSessions().iterator(); iterator.hasNext();) {
+        ((DebuggerSession)iterator.next()).refresh(false);
+      }
+    }
+  }
+
+  public void reset() {
+    myDataBinding.loadData(mySettings);
+  }
+
+  public boolean isModified() {
+    return myDataBinding.isModified(mySettings);
+  }
+
+  public String getHelpTopic() {
+    return "reference.dialogs.customizeThreadView";
+  }
+
+  public void disposeUIResources() {
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/ThreadsViewSettings.java b/java/debugger/impl/src/com/intellij/debugger/settings/ThreadsViewSettings.java
new file mode 100644
index 0000000..95fda53
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/settings/ThreadsViewSettings.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2000-2012 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.debugger.settings;
+
+import com.intellij.openapi.components.*;
+import com.intellij.util.xmlb.XmlSerializerUtil;
+
+@State(
+  name="ThreadsViewSettings",
+  storages= {
+    @Storage(
+      file = StoragePathMacros.APP_CONFIG + "/debugger.threadsview.xml"
+    )}
+)
+public class ThreadsViewSettings implements PersistentStateComponent<ThreadsViewSettings> {
+  public boolean SHOW_THREAD_GROUPS = false;
+  public boolean SHOW_LINE_NUMBER = true;
+  public boolean SHOW_CLASS_NAME = true;
+  public boolean SHOW_SOURCE_NAME = false;
+  public boolean SHOW_SYNTHETIC_FRAMES = true;
+  public boolean SHOW_CURRENT_THREAD = true;
+
+  public static ThreadsViewSettings getInstance() {
+    return ServiceManager.getService(ThreadsViewSettings.class);
+ }
+
+  public ThreadsViewSettings getState() {
+    return this;
+  }
+
+  public void loadState(final ThreadsViewSettings state) {
+    XmlSerializerUtil.copyBean(state, this);
+  }
+}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/ToggleButtonBinding.java b/java/debugger/impl/src/com/intellij/debugger/settings/ToggleButtonBinding.java
new file mode 100644
index 0000000..03b850a
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/settings/ToggleButtonBinding.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2000-2009 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.debugger.settings;
+
+import org.jetbrains.annotations.NonNls;
+
+import javax.swing.*;
+import java.lang.reflect.Field;
+
+/**
+ * @author Eugene Zhuravlev
+ * Date: Apr 12, 2005
+ */
+public class ToggleButtonBinding extends FieldDataBinding{
+  private final JToggleButton myToggleButton;
+
+  public ToggleButtonBinding(@NonNls String dataFieldName, JToggleButton checkBox) {
+    super(dataFieldName);
+    myToggleButton = checkBox;
+  }
+
+  public void doLoadData(Object from, Field field) throws IllegalAccessException {
+    final Boolean value = (Boolean)field.get(from);
+    myToggleButton.setSelected(value.booleanValue());
+  }
+
+  public void doSaveData(Object to, Field field) throws IllegalAccessException{
+    field.set(to, myToggleButton.isSelected()? Boolean.TRUE : Boolean.FALSE);
+  }
+
+  protected boolean isModified(Object obj, Field field) throws IllegalAccessException {
+    final Boolean value = (Boolean)field.get(obj);
+    return myToggleButton.isSelected() != value.booleanValue();
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/UserRenderersConfigurable.java b/java/debugger/impl/src/com/intellij/debugger/settings/UserRenderersConfigurable.java
new file mode 100644
index 0000000..c52f403
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/settings/UserRenderersConfigurable.java
@@ -0,0 +1,320 @@
+/*
+ * Copyright 2000-2009 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.debugger.settings;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.ui.tree.render.CompoundNodeRenderer;
+import com.intellij.debugger.ui.tree.render.NodeRenderer;
+import com.intellij.ide.util.ElementsChooser;
+import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.options.Configurable;
+import com.intellij.openapi.options.ConfigurationException;
+import com.intellij.openapi.options.SearchableConfigurable;
+import com.intellij.openapi.project.Project;
+import com.intellij.ui.DocumentAdapter;
+import com.intellij.util.IconUtil;
+import com.intellij.util.PlatformIcons;
+import com.intellij.util.containers.InternalIterator;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: Feb 19, 2005
+ */
+public class UserRenderersConfigurable implements SearchableConfigurable, Configurable.NoScroll {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.settings.UserRenderersConfigurable");
+  private static final Icon ADD_ICON = IconUtil.getAddIcon();
+  private static final Icon REMOVE_ICON = IconUtil.getRemoveIcon();
+  private static final Icon COPY_ICON = PlatformIcons.COPY_ICON;
+  private static final Icon UP_ICON = IconUtil.getMoveUpIcon();
+  private static final Icon DOWN_ICON = IconUtil.getMoveDownIcon();
+
+  private JTextField myNameField;
+  private ElementsChooser<NodeRenderer> myRendererChooser;
+  private NodeRenderer myCurrentRenderer = null;
+  private final CompoundRendererConfigurable myRendererDataConfigurable;
+
+  public UserRenderersConfigurable(@Nullable Project project) {
+    myRendererDataConfigurable = new CompoundRendererConfigurable(project);
+  }
+
+  public String getDisplayName() {
+    return DebuggerBundle.message("user.renderers.configurable.display.name");
+  }
+
+  public String getHelpTopic() {
+    return "reference.idesettings.debugger.typerenderers"; 
+  }
+
+  @NotNull
+  public String getId() {
+    return getHelpTopic();
+  }
+
+  public Runnable enableSearch(String option) {
+    return null;
+  }
+
+  public JComponent createComponent() {
+    final JPanel panel = new JPanel(new BorderLayout(4, 0));
+
+    final JComponent renderersList = createRenderersList();
+    final JComponent toolbar = createToolbar();
+    final JComponent rendererDataPanel = myRendererDataConfigurable.createComponent();
+
+    final JPanel left = new JPanel(new BorderLayout());
+
+    left.add(toolbar, BorderLayout.NORTH);
+    left.add(renderersList, BorderLayout.CENTER);
+
+    myNameField = new JTextField();
+    final JPanel nameFieldPanel = new JPanel(new BorderLayout());
+    nameFieldPanel.add(new JLabel(DebuggerBundle.message("label.user.renderers.configurable.renderer.name")), BorderLayout.WEST);
+    nameFieldPanel.add(myNameField, BorderLayout.CENTER);
+
+
+    final JPanel center = new JPanel(new BorderLayout(0, 4));
+
+    center.add(nameFieldPanel, BorderLayout.NORTH);
+    center.add(rendererDataPanel, BorderLayout.CENTER);
+
+    myNameField.getDocument().addDocumentListener(new DocumentAdapter() {
+      protected void textChanged(DocumentEvent e) {
+        if (myCurrentRenderer != null) {
+          myCurrentRenderer.setName(myNameField.getText());
+          myRendererChooser.refresh(myCurrentRenderer);
+        }
+      }
+    });
+
+    panel.add(left, BorderLayout.WEST);
+    panel.add(center, BorderLayout.CENTER);
+
+    return panel;
+  }
+
+  private JComponent createRenderersList() {
+    myRendererChooser = new ElementsChooser<NodeRenderer>(true);
+    myRendererChooser.getEmptyText().setText(DebuggerBundle.message("text.user.renderers.configurable.no.renderers"));
+
+    myRendererChooser.addElementsMarkListener(new ElementsChooser.ElementsMarkListener<NodeRenderer>() {
+      public void elementMarkChanged(final NodeRenderer element, final boolean isMarked) {
+        element.setEnabled(isMarked);
+      }
+    });
+    myRendererChooser.addListSelectionListener(new ListSelectionListener() {
+      public void valueChanged(ListSelectionEvent e) {
+        if (!e.getValueIsAdjusting()) {
+          updateCurrentRenderer(myRendererChooser.getSelectedElements());
+        }
+      }
+    });
+    return myRendererChooser;
+  }
+
+  private void updateCurrentRenderer(List<NodeRenderer> selectedElements) {
+    if (selectedElements.size() != 1) {
+      // multiselection
+      setCurrentRenderer(null);
+    }
+    else {
+      setCurrentRenderer(selectedElements.get(0));
+    }
+  }
+
+  private void setCurrentRenderer(NodeRenderer renderer) {
+    if (myCurrentRenderer == renderer) {
+      return;
+    }
+    try {
+      if (myRendererDataConfigurable.isModified()) {
+        myRendererDataConfigurable.apply();
+      }
+    }
+    catch (ConfigurationException e) {
+      LOG.error(e);
+    }
+    myCurrentRenderer = renderer;
+    if (renderer != null) {
+      myNameField.setEnabled(true);
+      myNameField.setText(renderer.getName());
+    }
+    else {
+      myNameField.setEnabled(false);
+      myNameField.setText("");
+    }
+    myRendererDataConfigurable.setRenderer(renderer);
+  }
+
+  private JComponent createToolbar() {
+    final DefaultActionGroup group = new DefaultActionGroup();
+    group.add(new AddAction());
+    group.add(new RemoveAction());
+    group.add(new CopyAction());
+    group.add(new MoveAction(true));
+    group.add(new MoveAction(false));
+    final ActionToolbar toolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, group, true);
+    return toolbar.getComponent();
+  }
+
+  public void apply() throws ConfigurationException {
+    myRendererDataConfigurable.apply();
+    flushTo(NodeRendererSettings.getInstance().getCustomRenderers());
+  }
+
+  private void flushTo(final RendererConfiguration rendererConfiguration) {
+    rendererConfiguration.removeAllRenderers();
+    final int count = myRendererChooser.getElementCount();
+    for (int idx = 0; idx < count; idx++) {
+      rendererConfiguration.addRenderer(myRendererChooser.getElementAt(idx));
+    }
+  }
+
+  public boolean isModified() {
+    if (myRendererDataConfigurable.isModified()) {
+      return true;
+    }
+    final NodeRendererSettings settings = NodeRendererSettings.getInstance();
+    final RendererConfiguration rendererConfiguration = settings.getCustomRenderers();
+    if (myRendererChooser.getElementCount() != rendererConfiguration.getRendererCount()) {
+      return true;
+    }
+    final RendererConfiguration uiConfiguration = new RendererConfiguration(settings);
+    flushTo(uiConfiguration);
+    return !uiConfiguration.equals(rendererConfiguration);
+  }
+
+  public void reset() {
+    myRendererChooser.removeAllElements();
+    final RendererConfiguration rendererConfiguration = NodeRendererSettings.getInstance().getCustomRenderers();
+    final ArrayList<NodeRenderer> elementsToSelect = new ArrayList<NodeRenderer>(1);
+    rendererConfiguration.iterateRenderers(new InternalIterator<NodeRenderer>() {
+      public boolean visit(final NodeRenderer renderer) {
+        final NodeRenderer clonedRenderer = (NodeRenderer)renderer.clone();
+        myRendererChooser.addElement(clonedRenderer, clonedRenderer.isEnabled());
+        if (elementsToSelect.size() == 0) {
+          elementsToSelect.add(clonedRenderer);
+        }
+        return true;
+      }
+    });
+    myRendererChooser.selectElements(elementsToSelect);
+    updateCurrentRenderer(elementsToSelect);
+    myRendererDataConfigurable.reset();
+  }
+
+  public void disposeUIResources() {
+    myRendererChooser.removeAllElements();
+    myRendererDataConfigurable.disposeUIResources();
+  }
+
+  private class AddAction extends AnAction {
+    public AddAction() {
+      super(DebuggerBundle.message("button.add"), DebuggerBundle.message("user.renderers.configurable.button.description.add"), ADD_ICON);
+    }
+
+    public void actionPerformed(AnActionEvent e) {
+      final NodeRenderer renderer = (NodeRenderer)NodeRendererSettings.getInstance().createRenderer(CompoundNodeRenderer.UNIQUE_ID);
+      renderer.setEnabled(true);
+      myRendererChooser.addElement(renderer, renderer.isEnabled());
+      SwingUtilities.invokeLater(new Runnable() {
+        public void run() {
+          myNameField.requestFocus();
+        }
+      });
+    }
+  }
+
+  private class RemoveAction extends AnAction {
+    public RemoveAction() {
+      super(DebuggerBundle.message("button.remove"), DebuggerBundle.message("user.renderers.configurable.button.description.remove"), REMOVE_ICON);
+    }
+
+    public void actionPerformed(AnActionEvent e) {
+      for (NodeRenderer selectedElement : myRendererChooser.getSelectedElements()) {
+        myRendererChooser.removeElement(selectedElement);
+      }
+    }
+
+    public void update(AnActionEvent e) {
+      super.update(e);
+      final Presentation presentation = e.getPresentation();
+      presentation.setEnabled(myRendererChooser.getSelectedElement() != null);
+    }
+  }
+
+  private class CopyAction extends AnAction {
+    public CopyAction() {
+      super(DebuggerBundle.message("button.copy"), DebuggerBundle.message("user.renderers.configurable.button.description.copy"), COPY_ICON);
+    }
+
+    public void actionPerformed(AnActionEvent e) {
+      final NodeRenderer selectedElement = myRendererChooser.getSelectedElement();
+      if (selectedElement != null) {
+        final NodeRenderer cloned = (NodeRenderer)selectedElement.clone();
+        myRendererChooser.addElement(cloned, true);
+      }
+    }
+
+    public void update(AnActionEvent e) {
+      super.update(e);
+      final Presentation presentation = e.getPresentation();
+      presentation.setEnabled(myRendererChooser.getSelectedElement() != null);
+    }
+  }
+
+  private class MoveAction extends AnAction {
+    private final boolean myMoveUp;
+
+    public MoveAction(boolean up) {
+      super(up? DebuggerBundle.message("button.move.up") : DebuggerBundle.message("button.move.down"),
+            up? DebuggerBundle.message("user.renderers.configurable.button.description.move.up") : DebuggerBundle.message("user.renderers.configurable.button.description.move.down"),
+            up? UP_ICON : DOWN_ICON );
+      myMoveUp = up;
+    }
+
+    public void actionPerformed(AnActionEvent e) {
+      final int selectedRow = myRendererChooser.getSelectedElementRow();
+      if (selectedRow < 0) {
+        return;
+      }
+      int newRow = selectedRow + (myMoveUp? -1 : 1);
+      if (newRow < 0) {
+        newRow = myRendererChooser.getElementCount() - 1;
+      }
+      else if (newRow >= myRendererChooser.getElementCount()) {
+        newRow = 0;
+      }
+      myRendererChooser.moveElement(myRendererChooser.getElementAt(selectedRow), newRow);
+    }
+
+    public void update(AnActionEvent e) {
+      super.update(e);
+      final Presentation presentation = e.getPresentation();
+      presentation.setEnabled(myRendererChooser.getSelectedElement() != null);
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/ViewsGeneralSettings.java b/java/debugger/impl/src/com/intellij/debugger/settings/ViewsGeneralSettings.java
new file mode 100644
index 0000000..8518e82
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/settings/ViewsGeneralSettings.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2000-2012 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.debugger.settings;
+
+import com.intellij.openapi.components.*;
+import com.intellij.openapi.util.DefaultJDOMExternalizer;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.WriteExternalException;
+import org.jdom.Element;
+
+@State(
+  name="ViewsSettings",
+  storages= {
+    @Storage(
+      file = StoragePathMacros.APP_CONFIG + "/debugger.frameview.xml"
+    )}
+)
+public class ViewsGeneralSettings implements PersistentStateComponent<Element> {
+  public boolean SHOW_OBJECTID = true;
+  public boolean HIDE_NULL_ARRAY_ELEMENTS = true;
+  public boolean AUTOSCROLL_TO_NEW_LOCALS = true;
+  public boolean ENABLE_AUTO_EXPRESSIONS = true;
+
+  public ViewsGeneralSettings() {
+  }
+
+  public static ViewsGeneralSettings getInstance() {
+    return ServiceManager.getService(ViewsGeneralSettings.class);
+  }
+
+  public void loadState(Element element) {
+    try {
+      DefaultJDOMExternalizer.readExternal(this, element);
+    }
+    catch (InvalidDataException e) {
+      // ignore
+    }
+  }
+
+  public Element getState() {
+    Element element = new Element("ViewsGeneralSettings");
+    try {
+      DefaultJDOMExternalizer.writeExternal(this, element);
+    }
+    catch (WriteExternalException e) {
+      // ignore
+    }
+    return element;
+  }
+
+  public boolean equals(Object object) {
+    if(!(object instanceof ViewsGeneralSettings)) return false;
+    ViewsGeneralSettings generalSettings = ((ViewsGeneralSettings) object);
+    return SHOW_OBJECTID == generalSettings.SHOW_OBJECTID &&
+           HIDE_NULL_ARRAY_ELEMENTS == generalSettings.HIDE_NULL_ARRAY_ELEMENTS &&
+           AUTOSCROLL_TO_NEW_LOCALS == generalSettings.AUTOSCROLL_TO_NEW_LOCALS;
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/CompletedInputDialog.java b/java/debugger/impl/src/com/intellij/debugger/ui/CompletedInputDialog.java
new file mode 100644
index 0000000..979723a
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/CompletedInputDialog.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui;
+
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.debugger.engine.evaluation.DefaultCodeFragmentFactory;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.PositionUtil;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.psi.PsiElement;
+
+import javax.swing.*;
+import java.awt.*;
+
+/**
+ * User: lex
+ * Date: Sep 16, 2003
+ * Time: 6:43:46 PM
+ */
+public class CompletedInputDialog extends DialogWrapper {
+  JPanel myPanel;
+  DebuggerExpressionComboBox myCombo;
+  PsiElement myContext;
+  Project myProject;
+  private JLabel myLabel;
+
+  public CompletedInputDialog(String title, String okText, Project project) {
+    super(project, false);
+    setTitle(title);
+    setOKButtonText(okText);
+    myProject = project;
+    setModal(false);
+    DebuggerContextImpl debuggerContext = (DebuggerManagerEx.getInstanceEx(project)).getContext();
+    myContext = PositionUtil.getContextElement(debuggerContext);
+    this.init();
+  }
+
+  public JComponent getPreferredFocusedComponent() {
+   return myCombo.getPreferredFocusedComponent();
+  }
+
+  protected JComponent createCenterPanel() {
+    myPanel = new JPanel(new GridBagLayout());
+    myLabel = new JLabel(DebuggerBundle.message("label.complete.input.dialog.expression"));
+    myPanel.add(myLabel, new GridBagConstraints(0, 0, GridBagConstraints.REMAINDER, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.NONE,
+            new Insets(0, 1, 0, 1), 0, 0));
+
+    myCombo = new DebuggerExpressionComboBox(myProject, myContext, "evaluation", DefaultCodeFragmentFactory.getInstance());
+    myCombo.selectAll();
+
+    myPanel.add(myCombo, new GridBagConstraints(0, 1, GridBagConstraints.REMAINDER, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
+            new Insets(0, 1, 0, 1), 0, 0));
+    myPanel.setPreferredSize(new Dimension(200, 50));
+    return myPanel;
+  }
+
+  public TextWithImports getExpressionText() {
+    return myCombo.getText();
+  }
+
+  public DebuggerExpressionComboBox getCombo() {
+    return myCombo;
+  }
+
+  public void setExpressionLabel(String text) {
+    myLabel.setText(text);
+  }
+
+  public void dispose() {
+    myCombo.dispose();
+    super.dispose();
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/CompletionEditor.java b/java/debugger/impl/src/com/intellij/debugger/ui/CompletionEditor.java
new file mode 100644
index 0000000..623d5c5
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/CompletionEditor.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui;
+
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.psi.PsiElement;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+
+public abstract class CompletionEditor extends JComponent{
+  public abstract void setText  (TextWithImports text);
+
+  public abstract TextWithImports getText();
+
+  public abstract void setContext(@Nullable PsiElement context);
+
+  public abstract PsiElement getContext();
+
+  public abstract void dispose();
+
+  public abstract String getRecentsId();
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerEditorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerEditorImpl.java
new file mode 100644
index 0000000..c60e811
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerEditorImpl.java
@@ -0,0 +1,317 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui;
+
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.engine.evaluation.CodeFragmentFactory;
+import com.intellij.debugger.engine.evaluation.CodeFragmentFactoryContextWrapper;
+import com.intellij.debugger.engine.evaluation.DefaultCodeFragmentFactory;
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.impl.PositionUtil;
+import com.intellij.ide.DataManager;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.actionSystem.DefaultActionGroup;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.event.DocumentListener;
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.popup.JBPopupFactory;
+import com.intellij.openapi.ui.popup.ListPopup;
+import com.intellij.openapi.util.IconLoader;
+import com.intellij.openapi.wm.IdeFocusManager;
+import com.intellij.psi.*;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.ui.ClickListener;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import javax.swing.border.EmptyBorder;
+import java.awt.*;
+import java.awt.event.MouseEvent;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author lex
+ */
+public abstract class DebuggerEditorImpl extends CompletionEditor{
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.DebuggerEditorImpl");
+
+  public static final char SEPARATOR = 13;
+
+  private final Project myProject;
+  private PsiElement myContext;
+
+  private final String myRecentsId;
+
+  private final List<DocumentListener> myDocumentListeners = new ArrayList<DocumentListener>();
+  private Document myCurrentDocument;
+  private final JLabel myChooseFactory = new JLabel();
+  private WeakReference<ListPopup> myPopup;
+
+  private final PsiTreeChangeListener myPsiListener = new PsiTreeChangeAdapter() {
+    public void childRemoved(@NotNull PsiTreeChangeEvent event) {
+      checkContext();
+    }
+    public void childReplaced(@NotNull PsiTreeChangeEvent event) {
+      checkContext();
+    }
+    public void childMoved(@NotNull PsiTreeChangeEvent event) {
+      checkContext();
+    }
+    private void checkContext() {
+      final PsiElement contextElement = getContext();
+      if(contextElement == null || !contextElement.isValid()) {
+        final DebuggerManagerEx manager = DebuggerManagerEx.getInstanceEx(myProject);
+        if (manager == null) {
+          LOG.error("Cannot obtain debugger manager for project " + myProject);
+        }
+        final DebuggerContextImpl context = manager.getContextManager().getContext();
+        final PsiElement newContextElement = PositionUtil.getContextElement(context);
+        setContext(newContextElement != null && newContextElement.isValid()? newContextElement : null);
+      }
+    }
+  };
+  private CodeFragmentFactory myFactory;
+  protected boolean myInitialFactory;
+
+  public DebuggerEditorImpl(Project project, PsiElement context, String recentsId, final CodeFragmentFactory factory) {
+    myProject = project;
+    myContext = context;
+    myRecentsId = recentsId;
+    PsiManager.getInstance(project).addPsiTreeChangeListener(myPsiListener);
+    setFactory(factory);
+    myInitialFactory = true;
+
+    setFocusable(false);
+
+    myChooseFactory.setToolTipText("Click to change the language");
+    myChooseFactory.setBorder(new EmptyBorder(0, 3, 0, 3));
+    new ClickListener() {
+      @Override
+      public boolean onClick(MouseEvent e, int clickCount) {
+        ListPopup oldPopup = myPopup != null ? myPopup.get() : null;
+        if (oldPopup != null && !oldPopup.isDisposed()) {
+          oldPopup.cancel();
+          myPopup = null;
+          return true;
+        }
+
+        if (myContext == null) {
+          return true;
+        }
+
+        ListPopup popup = createLanguagePopup();
+        popup.showUnderneathOf(myChooseFactory);
+        myPopup = new WeakReference<ListPopup>(popup);
+        return true;
+      }
+    }.installOn(myChooseFactory);
+  }
+
+  private ListPopup createLanguagePopup() {
+    DefaultActionGroup actions = new DefaultActionGroup();
+    for (final CodeFragmentFactory fragmentFactory : DebuggerUtilsEx.getCodeFragmentFactories(myContext)) {
+      actions.add(new AnAction(fragmentFactory.getFileType().getLanguage().getDisplayName(), null, fragmentFactory.getFileType().getIcon()) {
+        @Override
+        public void actionPerformed(AnActionEvent e) {
+          setFactory(fragmentFactory);
+          setText(getText());
+          IdeFocusManager.getInstance(getProject()).requestFocus(DebuggerEditorImpl.this, true);
+        }
+      });
+    }
+
+    DataContext dataContext = DataManager.getInstance().getDataContext(this);
+    return JBPopupFactory.getInstance().createActionGroupPopup("Choose language", actions, dataContext,
+                                                                          JBPopupFactory.ActionSelectionAid.SPEEDSEARCH,
+                                                                          false);
+  }
+
+  @Override
+  public void setEnabled(boolean enabled) {
+    myChooseFactory.setEnabled(enabled);
+    super.setEnabled(enabled);
+  }
+
+  protected TextWithImports createItem(Document document, Project project) {
+    if (document != null) {
+      PsiDocumentManager.getInstance(project).commitDocument(document);
+      PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(document);
+      if (psiFile != null) {
+        return createText(psiFile.getText(), ((JavaCodeFragment)psiFile).importsToString());
+      }
+    }
+
+    return createText("");
+  }
+
+  protected TextWithImports createText(String text) {
+    return createText(text, "");
+  }
+
+  protected abstract TextWithImports createText(String text, String importsString);
+
+  public abstract JComponent getPreferredFocusedComponent();
+
+  public void setContext(@Nullable PsiElement context) {
+    myContext = context;
+
+    List<CodeFragmentFactory> factories = DebuggerUtilsEx.getCodeFragmentFactories(context);
+    boolean many = factories.size() > 1;
+    if (myInitialFactory) {
+      myInitialFactory = false;
+      setFactory(factories.get(0));
+      myChooseFactory.setVisible(many);
+    }
+    myChooseFactory.setVisible(myChooseFactory.isVisible() || many);
+    myChooseFactory.setEnabled(many && factories.contains(myFactory));
+
+    updateEditorUi();
+  }
+
+  @Override
+  public void setText(TextWithImports text) {
+    doSetText(text);
+    updateEditorUi();
+  }
+
+  protected abstract void doSetText(TextWithImports text);
+
+  protected abstract void updateEditorUi();
+
+  public PsiElement getContext() {
+    return myContext;
+  }
+
+  protected Project getProject() {
+    return myProject;
+  }
+
+  public void requestFocus() {
+    getPreferredFocusedComponent().requestFocus();
+  }
+
+  @Nullable
+  protected Document createDocument(TextWithImports item) {
+    LOG.assertTrue(myContext == null || myContext.isValid());
+
+    if(item == null) {
+      item = createText("");
+    }
+    JavaCodeFragment codeFragment = getCurrentFactory().createPresentationCodeFragment(item, myContext, getProject());
+    codeFragment.forceResolveScope(GlobalSearchScope.allScope(myProject));
+    if (myContext != null) {
+      final PsiClass contextClass = PsiTreeUtil.getNonStrictParentOfType(myContext, PsiClass.class);
+      if (contextClass != null) {
+        final PsiClassType contextType = JavaPsiFacade.getInstance(codeFragment.getProject()).getElementFactory().createType(contextClass);
+        codeFragment.setThisType(contextType);
+      }
+    }
+
+    if(myCurrentDocument != null) {
+      for (DocumentListener documentListener : myDocumentListeners) {
+        myCurrentDocument.removeDocumentListener(documentListener);
+      }
+    }
+
+    myCurrentDocument = PsiDocumentManager.getInstance(getProject()).getDocument(codeFragment);
+
+    if (myCurrentDocument != null) {
+      for (DocumentListener documentListener : myDocumentListeners) {
+        myCurrentDocument.addDocumentListener(documentListener);
+      }
+    }
+
+    return myCurrentDocument;
+  }
+
+  public String getRecentsId() {
+    return myRecentsId;
+  }
+
+  public void addRecent(TextWithImports text) {
+    if(getRecentsId() != null && text != null && !"".equals(text.getText())){
+      DebuggerRecents.getInstance(getProject()).addRecent(getRecentsId(), text);
+    }
+  }
+
+  public void addDocumentListener(DocumentListener listener) {
+    myDocumentListeners.add(listener);
+    if(myCurrentDocument != null) {
+      myCurrentDocument.addDocumentListener(listener);
+    }
+  }
+
+  public void removeDocumentListener(DocumentListener listener) {
+    myDocumentListeners.remove(listener);
+    if(myCurrentDocument != null) {
+      myCurrentDocument.removeDocumentListener(listener);
+    }
+  }
+
+  public void dispose() {
+    PsiManager.getInstance(myProject).removePsiTreeChangeListener(myPsiListener);
+    myCurrentDocument = null;
+  }
+
+  @NotNull
+  public static CodeFragmentFactory findAppropriateFactory(@NotNull TextWithImports text, @NotNull PsiElement context) {
+    for (CodeFragmentFactory factory : DebuggerUtilsEx.getCodeFragmentFactories(context)) {
+      if (factory.getFileType().equals(text.getFileType())) {
+        return factory;
+      }
+    }
+    return DefaultCodeFragmentFactory.getInstance();
+  }
+
+  protected void restoreFactory(TextWithImports text) {
+    FileType fileType = text.getFileType();
+    if (fileType == null) return;
+    if (myContext == null) return;
+
+    setFactory(findAppropriateFactory(text, myContext));
+  }
+
+  private void setFactory(@NotNull final CodeFragmentFactory factory) {
+    myFactory = factory;
+    Icon icon = getCurrentFactory().getFileType().getIcon();
+    myChooseFactory.setIcon(icon);
+    myChooseFactory.setDisabledIcon(IconLoader.getDisabledIcon(icon));
+  }
+
+  protected CodeFragmentFactory getCurrentFactory() {
+    return myFactory instanceof CodeFragmentFactoryContextWrapper ? myFactory : new CodeFragmentFactoryContextWrapper(myFactory);
+  }
+
+  protected JPanel addChooseFactoryLabel(JComponent component, boolean top) {
+    JPanel panel = new JPanel(new BorderLayout());
+    panel.add(component, BorderLayout.CENTER);
+
+    JPanel factoryPanel = new JPanel(new BorderLayout());
+    factoryPanel.add(myChooseFactory, top ? BorderLayout.NORTH : BorderLayout.CENTER);
+    panel.add(factoryPanel, BorderLayout.WEST);
+    return panel;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerExpressionComboBox.java b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerExpressionComboBox.java
new file mode 100644
index 0000000..9f9cf4a
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerExpressionComboBox.java
@@ -0,0 +1,315 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui;
+
+import com.intellij.debugger.engine.evaluation.*;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.ComboBox;
+import com.intellij.openapi.util.Key;
+import com.intellij.psi.PsiElement;
+import com.intellij.ui.EditorComboBoxEditor;
+import com.intellij.ui.EditorComboBoxRenderer;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import javax.swing.plaf.basic.ComboPopup;
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author ven
+ */
+public class DebuggerExpressionComboBox extends DebuggerEditorImpl {
+  public static final Key<String> KEY = Key.create("DebuggerComboBoxEditor.KEY");
+  public static final int MAX_ROWS = 20;
+
+  private MyEditorComboBoxEditor myEditor;
+  private ComboBox myComboBox;
+
+  private class MyEditorComboBoxEditor extends EditorComboBoxEditor {
+
+    public MyEditorComboBoxEditor(Project project, FileType fileType) {
+      super(project, fileType);
+    }
+
+    public Object getItem() {
+      Document document = (Document)super.getItem();
+      return createItem(document, getProject());
+    }
+
+    public void setItem(Object item) {
+      TextWithImports twi = (TextWithImports)item;
+      if (twi != null) {
+        restoreFactory(twi);
+      }
+      final Document document = createDocument(twi);
+      getEditorComponent().setNewDocumentAndFileType(getCurrentFactory().getFileType(), document);
+      super.setItem(document);
+      /* Causes PSI being modified from PSI events. See IDEADEV-22102
+      final Editor editor = getEditor();
+      if (editor != null) {
+        DaemonCodeAnalyzer.getInstance(getProject()).updateVisibleHighlighters(editor);
+      }
+      */
+    }
+
+  }
+
+  public DebuggerExpressionComboBox(Project project, @NonNls String recentsId) {
+    this(project, null, recentsId, DefaultCodeFragmentFactory.getInstance());
+  }
+
+  public DebuggerExpressionComboBox(Project project, PsiElement context, @NonNls String recentsId, final CodeFragmentFactory factory) {
+    super(project, context, recentsId, factory);
+    setLayout(new BorderLayout(0, 0));
+
+    myComboBox = new ComboBox(new MyComboboxModel(getRecents()), 100);
+    myComboBox.setSwingPopup(false);
+
+    // Have to turn this off because when used in DebuggerTreeInplaceEditor, the combobox popup is hidden on every change of selection
+    // See comment to SynthComboBoxUI.FocusHandler.focusLost()
+    myComboBox.setLightWeightPopupEnabled(false);
+
+    myEditor = new MyEditorComboBoxEditor(getProject(), getCurrentFactory().getFileType());
+    myComboBox.setRenderer(new EditorComboBoxRenderer(myEditor));
+
+    myComboBox.setEditable(true);
+    myComboBox.setEditor(myEditor);
+    add(addChooseFactoryLabel(myComboBox, false));
+  }
+
+  public void selectPopupValue() {
+    selectAll();
+    final Object currentPopupValue = getCurrentPopupValue();
+    if (currentPopupValue != null) {
+      myComboBox.getModel().setSelectedItem(currentPopupValue);
+      myComboBox.getEditor().setItem(currentPopupValue);
+    }
+
+    myComboBox.setPopupVisible(false);
+  }
+
+  public boolean isPopupVisible() {
+    return myComboBox.isVisible() && myComboBox.isPopupVisible();
+  }
+
+  public void setPopupVisible(final boolean b) {
+    myComboBox.setPopupVisible(b);
+  }
+
+  @Nullable
+  public Object getCurrentPopupValue() {
+    if (!isPopupVisible()) return null;
+
+    final ComboPopup popup = myComboBox.getPopup();
+    if (popup != null) {
+      return popup.getList().getSelectedValue();
+    }
+
+    return null;
+  }
+
+  @Override
+  protected void doSetText(TextWithImports item) {
+    final String itemText = item.getText().replace('\n', ' ');
+    restoreFactory(item);
+    item.setText(itemText);
+    if (!"".equals(itemText)) {
+      if (myComboBox.getItemCount() == 0 || !item.equals(myComboBox.getItemAt(0))) {
+        myComboBox.insertItemAt(item, 0);
+      }
+    }
+    if (myComboBox.getItemCount() > 0) {
+      myComboBox.setSelectedIndex(0);
+    }
+
+    myComboBox.getEditor().setItem(item);
+  }
+
+  @Override
+  protected void updateEditorUi() {
+  }
+
+  public TextWithImports getText() {
+    return (TextWithImports)myComboBox.getEditor().getItem();
+  }
+
+  @Nullable
+  private List<TextWithImports> getRecents() {
+    final String recentsId = getRecentsId();
+    if (recentsId != null) {
+      final List<TextWithImports> result = new ArrayList<TextWithImports>();
+      LinkedList<TextWithImports> recents = DebuggerRecents.getInstance(getProject()).getRecents(getRecentsId());
+      for (final TextWithImports evaluationText : recents) {
+        if (evaluationText.getText().indexOf('\n') == -1) {
+          result.add(evaluationText);
+        }
+      }
+
+      return result;
+    }
+
+    return null;
+  }
+
+  public Dimension getMinimumSize() {
+    Dimension size = super.getMinimumSize();
+    size.width = 100;
+    return size;
+  }
+
+  public TextWithImports createText(String text, String importsString) {
+    return new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, text, importsString, getCurrentFactory().getFileType());
+  }
+
+  @Override
+  public void setEnabled(boolean enabled) {
+    super.setEnabled(enabled);
+    myComboBox.setEnabled(enabled);
+    //if (enabled) {
+    //  final ComboBoxEditor editor = myComboBox.getEditor();
+    //  editor.setItem(editor.getItem());
+    //}
+  }
+
+  public JComponent getPreferredFocusedComponent() {
+    return (JComponent)myComboBox.getEditor().getEditorComponent();
+  }
+
+  public void selectAll() {
+    myComboBox.getEditor().selectAll();
+  }
+
+  public Editor getEditor() {
+    return myEditor.getEditor();
+  }
+
+  public JComponent getEditorComponent() {
+    return (JComponent)myEditor.getEditorComponent();
+  }
+
+  public void addRecent(TextWithImports text) {
+    if (text.getText().length() != 0) {
+      final Component editorComponent = myComboBox.getEditor().getEditorComponent();
+      final boolean focusOwner = editorComponent.isFocusOwner();
+      super.addRecent(text);
+      myComboBox.insertItemAt(text, 0);
+      myComboBox.setSelectedIndex(0);
+
+      if (focusOwner) {
+        editorComponent.requestFocus();
+      }
+    }
+  }
+
+  private static class MyComboboxModel extends AbstractListModel implements MutableComboBoxModel {
+    private List<TextWithImports> myItems = new ArrayList<TextWithImports>();
+    private int mySelectedIndex = -1;
+
+    private MyComboboxModel(@Nullable final List<TextWithImports> recents) {
+      if (recents != null) {
+        myItems = recents;
+      }
+    }
+
+    @Override
+    public void setSelectedItem(final Object anItem) {
+      final int oldSelectedIndex = mySelectedIndex;
+      mySelectedIndex = anItem instanceof TextWithImports ? myItems.indexOf(anItem) : -1;
+      if (oldSelectedIndex != mySelectedIndex) fireContentsChanged(this, -1, -1);
+    }
+
+    @Override
+    public Object getSelectedItem() {
+      return mySelectedIndex == -1 || mySelectedIndex > myItems.size() - 1 ? null : myItems.get(mySelectedIndex);
+    }
+
+    @Override
+    public int getSize() {
+      return myItems.size();
+    }
+
+    @Override
+    public Object getElementAt(int index) {
+      return myItems.get(index);
+    }
+
+    @Override
+    public void addElement(final Object obj) {
+      insertElementAt(obj, myItems.size() - 1);
+
+      if (mySelectedIndex == -1 && myItems.size() == 1 && obj != null) {
+        setSelectedItem(obj);
+      }
+    }
+
+    @Override
+    public void removeElement(Object obj) {
+      removeElement(obj, true);
+    }
+
+    public void removeElement(final Object obj, final boolean checkSelection) {
+      if (!(obj instanceof TextWithImports)) throw new IllegalArgumentException();
+      final int index = myItems.indexOf((TextWithImports)obj);
+      if (index != -1) {
+        myItems.remove(index);
+
+        if (checkSelection) {
+          if (mySelectedIndex == index) {
+            if (myItems.size() == 0) {
+              setSelectedItem(null);
+            }
+            else if (index > myItems.size() - 1) {
+              setSelectedItem(myItems.get(myItems.size() - 1));
+            }
+          }
+
+          fireIntervalRemoved(this, index, index);
+        }
+      }
+    }
+
+    @Override
+    public void insertElementAt(final Object obj, final int index) {
+      if (!(obj instanceof TextWithImports)) throw new IllegalArgumentException();
+      removeElement(obj, false); // remove duplicate entry if any
+
+      myItems.add(index, (TextWithImports)obj);
+      fireIntervalAdded(this, index, index);
+
+      if (myItems.size() > MAX_ROWS) {
+        for (int i = myItems.size() - 1; i > MAX_ROWS - 1; i--) {
+          myItems.remove(i);
+        }
+
+        // will not fire events here to not recreate the editor
+        //fireIntervalRemoved(this, myItems.size() - 1, MAX_ROWS - 1);
+      }
+    }
+
+    @Override
+    public void removeElementAt(final int index) {
+      if (index < 0 || index > myItems.size() - 1) throw new IndexOutOfBoundsException();
+      removeElement(myItems.get(index));
+    }
+  }
+}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerExpressionTextField.java b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerExpressionTextField.java
new file mode 100644
index 0000000..8dbdb3d
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerExpressionTextField.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui;
+
+import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
+import com.intellij.debugger.engine.evaluation.CodeFragmentKind;
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.debugger.engine.evaluation.TextWithImportsImpl;
+import com.intellij.debugger.engine.evaluation.DefaultCodeFragmentFactory;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.fileTypes.StdFileTypes;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
+import com.intellij.ui.EditorTextField;
+import org.jetbrains.annotations.NonNls;
+
+import javax.swing.*;
+import java.awt.*;
+
+public class DebuggerExpressionTextField extends DebuggerEditorImpl {
+  private final EditorTextField myEditor;
+  private final JTextField myStubField = new JTextField();
+  private final JPanel myMainPanel = new JPanel(new CardLayout());
+  private static final @NonNls String EDITOR = "editor";
+  private static final @NonNls String STUB = "stub";
+
+  public DebuggerExpressionTextField(Project project, PsiElement context, final @NonNls String recentsId) {
+    super(project, context, recentsId, DefaultCodeFragmentFactory.getInstance());
+    myStubField.setEnabled(false);
+    myEditor = new EditorTextField("", project, StdFileTypes.JAVA);
+    setLayout(new BorderLayout());
+    myMainPanel.add(myStubField, STUB);
+    myMainPanel.add(addChooseFactoryLabel(myEditor, false), EDITOR);
+    add(myMainPanel, BorderLayout.CENTER);
+    ((CardLayout)myMainPanel.getLayout()).show(myMainPanel, isEnabled()? EDITOR : STUB);
+    setText(new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, ""));
+  }
+
+  public JComponent getPreferredFocusedComponent() {
+    return myEditor.getEditor().getContentComponent();
+  }
+
+  public void selectAll() {
+    myEditor.selectAll();
+  }
+
+  public TextWithImports getText() {
+    return createItem(myEditor.getDocument(), getProject());
+  }
+
+  @Override
+  protected void doSetText(TextWithImports text) {
+    restoreFactory(text);
+    myEditor.setNewDocumentAndFileType(getCurrentFactory().getFileType(), createDocument(text));
+  }
+
+  @Override
+  protected void updateEditorUi() {
+    final Editor editor = myEditor.getEditor();
+    if (editor != null) {
+      DaemonCodeAnalyzer.getInstance(getProject()).updateVisibleHighlighters(editor);
+    }
+  }
+
+  public TextWithImports createText(String text, String importsString) {
+    return new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, text, importsString, getCurrentFactory().getFileType());
+  }
+
+  public void setEnabled(boolean enabled) {
+    if (isEnabled() != enabled) {
+      super.setEnabled(enabled);
+      final TextWithImports text = getText();
+      myStubField.setText(text.getText());
+      ((CardLayout)myMainPanel.getLayout()).show(myMainPanel, enabled? EDITOR : STUB);
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerPanelsManager.java b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerPanelsManager.java
new file mode 100644
index 0000000..9cb61ef
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerPanelsManager.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui;
+
+import com.intellij.debugger.*;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerContextListener;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.debugger.impl.DebuggerStateManager;
+import com.intellij.debugger.ui.impl.MainWatchPanel;
+import com.intellij.debugger.ui.tree.render.BatchEvaluator;
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.ExecutionManager;
+import com.intellij.execution.Executor;
+import com.intellij.execution.configurations.RemoteConnection;
+import com.intellij.execution.configurations.RunProfileState;
+import com.intellij.execution.executors.DefaultDebugExecutor;
+import com.intellij.execution.process.ProcessHandler;
+import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.execution.runners.ProgramRunner;
+import com.intellij.execution.ui.RunContentDescriptor;
+import com.intellij.execution.ui.RunContentListener;
+import com.intellij.execution.ui.RunContentManager;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.components.ProjectComponent;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.colors.EditorColorsListener;
+import com.intellij.openapi.editor.colors.EditorColorsManager;
+import com.intellij.openapi.editor.colors.EditorColorsScheme;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Disposer;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.HashMap;
+
+public class DebuggerPanelsManager implements ProjectComponent {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.DebuggerPanelsManager");
+
+  private final Project myProject;
+  private final ExecutionManager myExecutionManager;
+
+  private final PositionHighlighter myEditorManager;
+  private final HashMap<ProcessHandler, DebuggerSessionTab> mySessionTabs = new HashMap<ProcessHandler, DebuggerSessionTab>();
+
+  public DebuggerPanelsManager(Project project, final EditorColorsManager colorsManager, ExecutionManager executionManager) {
+    myProject = project;
+    myExecutionManager = executionManager;
+
+    myEditorManager = new PositionHighlighter(myProject, getContextManager());
+
+    final EditorColorsListener myColorsListener = new EditorColorsListener() {
+      public void globalSchemeChange(EditorColorsScheme scheme) {
+        myEditorManager.updateContextPointDescription();
+      }
+    };
+    colorsManager.addEditorColorsListener(myColorsListener);
+    Disposer.register(project, new Disposable() {
+      public void dispose() {
+        colorsManager.removeEditorColorsListener(myColorsListener);
+      }
+    });
+
+    getContextManager().addListener(new DebuggerContextListener() {
+      public void changeEvent(final DebuggerContextImpl newContext, int event) {
+        if (event == DebuggerSession.EVENT_PAUSE) {
+          DebuggerInvocationUtil.invokeLater(myProject, new Runnable() {
+            public void run() {
+              toFront(newContext.getDebuggerSession());
+            }
+          });
+        }
+      }
+    });
+  }
+
+  private DebuggerStateManager getContextManager() {
+    return DebuggerManagerEx.getInstanceEx(myProject).getContextManager();
+  }
+
+  @Nullable
+  public RunContentDescriptor attachVirtualMachine(Executor executor,
+                                                   ProgramRunner runner,
+                                                   ExecutionEnvironment environment,
+                                                   RunProfileState state,
+                                                   RunContentDescriptor reuseContent,
+                                                   RemoteConnection remoteConnection,
+                                                   boolean pollConnection) throws ExecutionException {
+    return attachVirtualMachine(new DefaultDebugUIEnvironment(myProject,
+                                                            executor,
+                                                            runner,
+                                                            environment,
+                                                            state,
+                                                            reuseContent,
+                                                            remoteConnection,
+                                                            pollConnection));
+  }
+
+  @Nullable
+  public RunContentDescriptor attachVirtualMachine(DebugUIEnvironment environment) throws ExecutionException {
+    final DebugEnvironment modelEnvironment = environment.getEnvironment();
+    final DebuggerSession debuggerSession = DebuggerManagerEx.getInstanceEx(myProject).attachVirtualMachine(modelEnvironment);
+    if (debuggerSession == null) {
+      return null;
+    }
+
+    final DebugProcessImpl debugProcess = debuggerSession.getProcess();
+    if (debugProcess.isDetached() || debugProcess.isDetaching()) {
+      debuggerSession.dispose();
+      return null;
+    }
+    if (modelEnvironment.isRemote()) {
+      // optimization: that way BatchEvaluator will not try to lookup the class file in remote VM
+      // which is an expensive operation when executed first time
+      debugProcess.putUserData(BatchEvaluator.REMOTE_SESSION_KEY, Boolean.TRUE);
+    }
+
+    final DebuggerSessionTab sessionTab = new DebuggerSessionTab(myProject, modelEnvironment.getSessionName(), environment.getIcon());
+    Disposer.register(myProject, sessionTab);
+    RunContentDescriptor runContentDescriptor = sessionTab.attachToSession(debuggerSession, environment);
+    RunContentDescriptor reuseContent = environment.getReuseContent();
+    if (reuseContent != null) {
+      final ProcessHandler prevHandler = reuseContent.getProcessHandler();
+      if (prevHandler != null) {
+        final DebuggerSessionTab prevSession = mySessionTabs.get(prevHandler);
+        if (prevSession != null) {
+          sessionTab.reuse(prevSession);
+        }
+      }
+    }
+    mySessionTabs.put(runContentDescriptor.getProcessHandler(), sessionTab);
+    return runContentDescriptor;
+  }
+
+
+  public void projectOpened() {
+    final RunContentManager contentManager = myExecutionManager.getContentManager();
+    LOG.assertTrue(contentManager != null, "Content manager is null");
+
+    final RunContentListener myContentListener = new RunContentListener() {
+      public void contentSelected(RunContentDescriptor descriptor) {
+        DebuggerSessionTab sessionTab = descriptor != null ? getSessionTab(descriptor.getProcessHandler()) : null;
+
+        if (sessionTab != null) {
+          getContextManager()
+            .setState(sessionTab.getContextManager().getContext(), sessionTab.getSession().getState(), DebuggerSession.EVENT_CONTEXT, null);
+        }
+        else {
+          getContextManager()
+            .setState(DebuggerContextImpl.EMPTY_CONTEXT, DebuggerSession.STATE_DISPOSED, DebuggerSession.EVENT_CONTEXT, null);
+        }
+      }
+
+      public void contentRemoved(RunContentDescriptor descriptor) {
+        DebuggerSessionTab sessionTab = getSessionTab(descriptor.getProcessHandler());
+        if (sessionTab != null) {
+          mySessionTabs.remove(descriptor.getProcessHandler());
+          Disposer.dispose(sessionTab);
+        }
+      }
+    };
+
+    contentManager.addRunContentListener(myContentListener, DefaultDebugExecutor.getDebugExecutorInstance());
+    Disposer.register(myProject, new Disposable() {
+      public void dispose() {
+        contentManager.removeRunContentListener(myContentListener);
+      }
+    });
+  }
+
+  public void projectClosed() {
+  }
+
+  @NotNull
+  public String getComponentName() {
+    return "DebuggerPanelsManager";
+  }
+
+  public void initComponent() {
+  }
+
+  public void disposeComponent() {
+  }
+
+  public static DebuggerPanelsManager getInstance(Project project) {
+    return project.getComponent(DebuggerPanelsManager.class);
+  }
+
+  @Nullable
+  public MainWatchPanel getWatchPanel() {
+    DebuggerSessionTab sessionTab = getSessionTab();
+    return sessionTab != null ? sessionTab.getWatchPanel() : null;
+  }
+
+  @Nullable
+  public DebuggerSessionTab getSessionTab() {
+    DebuggerContextImpl context = DebuggerManagerEx.getInstanceEx(myProject).getContext();
+    return getSessionTab(context.getDebuggerSession());
+  }
+
+  public void showFramePanel() {
+    DebuggerSessionTab sessionTab = getSessionTab();
+    if (sessionTab != null) {
+      sessionTab.showFramePanel();
+    }
+  }
+
+  public void toFront(DebuggerSession session) {
+    DebuggerSessionTab sessionTab = getSessionTab(session);
+    if (sessionTab != null) {
+      sessionTab.toFront();
+    }
+  }
+
+  private DebuggerSessionTab getSessionTab(ProcessHandler processHandler) {
+    return mySessionTabs.get(processHandler);
+  }
+
+  @Nullable
+  private DebuggerSessionTab getSessionTab(DebuggerSession session) {
+    return session != null ? getSessionTab(session.getProcess().getExecutionResult().getProcessHandler()) : null;
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerRecents.java b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerRecents.java
new file mode 100644
index 0000000..c314a0c
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerRecents.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui;
+
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.util.containers.HashMap;
+
+import java.util.LinkedList;
+import java.util.Map;
+
+/**
+ * @author Lex
+ */
+public class DebuggerRecents {  
+  private final Map<Object, LinkedList<TextWithImports>> myRecentExpressions = new HashMap<Object, LinkedList<TextWithImports>>();
+
+  public static DebuggerRecents getInstance(Project project) {
+    return ServiceManager.getService(project, DebuggerRecents.class);
+  }
+
+  public LinkedList<TextWithImports> getRecents(Object id) {
+    LinkedList<TextWithImports> result = myRecentExpressions.get(id);
+    if(result == null){
+      result = new LinkedList<TextWithImports>();
+      myRecentExpressions.put(id, result);
+    }
+    return result;
+  }
+
+  public void addRecent(Object id, TextWithImports recent) {
+    LinkedList<TextWithImports> recents = getRecents(id);
+    if(recents.size() >= DebuggerExpressionComboBox.MAX_ROWS) {
+      recents.removeLast();
+    }
+    recents.remove(recent);
+    recents.addFirst(recent);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerSessionTab.java b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerSessionTab.java
new file mode 100644
index 0000000..9feb928
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerSessionTab.java
@@ -0,0 +1,592 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui;
+
+import com.intellij.debugger.DebugUIEnvironment;
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.actions.DebuggerActions;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerContextListener;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.debugger.impl.DebuggerStateManager;
+import com.intellij.debugger.settings.DebuggerSettings;
+import com.intellij.debugger.ui.impl.MainWatchPanel;
+import com.intellij.debugger.ui.impl.ThreadsPanel;
+import com.intellij.debugger.ui.impl.VariablesPanel;
+import com.intellij.debugger.ui.impl.WatchDebuggerTree;
+import com.intellij.debugger.ui.impl.watch.*;
+import com.intellij.execution.DefaultExecutionResult;
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.ExecutionManager;
+import com.intellij.execution.ExecutionResult;
+import com.intellij.execution.configurations.RunProfile;
+import com.intellij.execution.executors.DefaultDebugExecutor;
+import com.intellij.execution.filters.ExceptionFilters;
+import com.intellij.execution.filters.Filter;
+import com.intellij.execution.filters.TextConsoleBuilder;
+import com.intellij.execution.filters.TextConsoleBuilderFactory;
+import com.intellij.execution.ui.ConsoleView;
+import com.intellij.execution.ui.ExecutionConsoleEx;
+import com.intellij.execution.ui.RunContentDescriptor;
+import com.intellij.execution.ui.layout.PlaceInGrid;
+import com.intellij.icons.AllIcons;
+import com.intellij.idea.ActionsBundle;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.ui.content.AlertIcon;
+import com.intellij.ui.content.Content;
+import com.intellij.ui.content.ContentManagerAdapter;
+import com.intellij.ui.content.ContentManagerEvent;
+import com.intellij.ui.content.tabs.PinToolwindowTabAction;
+import com.intellij.unscramble.ThreadDumpPanel;
+import com.intellij.unscramble.ThreadState;
+import com.intellij.xdebugger.XDebuggerBundle;
+import com.intellij.xdebugger.impl.actions.XDebuggerActions;
+import com.intellij.xdebugger.impl.ui.DebuggerSessionTabBase;
+import com.intellij.xdebugger.impl.ui.XDebuggerUIConstants;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import javax.swing.tree.TreePath;
+import java.util.List;
+
+public class DebuggerSessionTab extends DebuggerSessionTabBase implements Disposable {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.DebuggerSessionTab");
+
+  private final VariablesPanel myVariablesPanel;
+  private final MainWatchPanel myWatchPanel;
+
+  private volatile DebuggerSession myDebuggerSession;
+
+  private final MyDebuggerStateManager myStateManager = new MyDebuggerStateManager();
+
+  private final FramesPanel myFramesPanel;
+  private DebugUIEnvironment myDebugUIEnvironment;
+
+  private final ThreadsPanel myThreadsPanel;
+  private static final String THREAD_DUMP_CONTENT_PREFIX = "Dump";
+  private final Icon myIcon;
+
+  public DebuggerSessionTab(final Project project, final String sessionName, @Nullable final Icon icon) {
+    super(project, "JavaDebugger", sessionName);
+
+    myIcon = icon;
+
+    final DefaultActionGroup focus = new DefaultActionGroup();
+    focus.add(ActionManager.getInstance().getAction("Debugger.FocusOnBreakpoint"));
+    myUi.getOptions().setAdditionalFocusActions(focus);
+
+    final DebuggerSettings debuggerSettings = DebuggerSettings.getInstance();
+    if (!ApplicationManager.getApplication().isUnitTestMode()) {
+      getContextManager().addListener(new DebuggerContextListener() {
+        public void changeEvent(DebuggerContextImpl newContext, int event) {
+          switch (event) {
+            case DebuggerSession.EVENT_DETACHED:
+              myUi.updateActionsNow();
+
+              if (debuggerSettings.HIDE_DEBUGGER_ON_PROCESS_TERMINATION) {
+                try {
+                  ExecutionManager.getInstance(getProject()).getContentManager().hideRunContent(DefaultDebugExecutor.getDebugExecutorInstance(), myRunContentDescriptor);
+                }
+                catch (NullPointerException e) {
+                  //if we can get closeProcess after the project have been closed
+                  LOG.debug(e);
+                }
+              }
+              break;
+          }
+        }
+      });
+    }
+
+    DefaultActionGroup topToolbar = new DefaultActionGroup();
+    ActionManager actionManager = ActionManager.getInstance();
+    topToolbar.addAll(getCustomizedActionGroup(XDebuggerActions.TOOL_WINDOW_TOP_TOOLBAR_GROUP));
+    topToolbar.add(actionManager.getAction(DebuggerActions.POP_FRAME), new Constraints(Anchor.AFTER, XDebuggerActions.STEP_OUT));
+    topToolbar.add(Separator.getInstance(), new Constraints(Anchor.BEFORE, DebuggerActions.POP_FRAME));
+    topToolbar.add(Separator.getInstance(), new Constraints(Anchor.AFTER, DebuggerActions.POP_FRAME));
+    myUi.getOptions().setTopToolbar(topToolbar, ActionPlaces.DEBUGGER_TOOLBAR);
+
+
+    myWatchPanel = new MainWatchPanel(getProject(), getContextManager());
+    myFramesPanel = new FramesPanel(getProject(), getContextManager());
+
+
+    final AlertIcon breakpointAlert = new AlertIcon(AllIcons.Debugger.BreakpointAlert);
+
+    // watches
+    Content watches = myUi.createContent(DebuggerContentInfo.WATCHES_CONTENT, myWatchPanel, XDebuggerBundle.message("debugger.session.tab.watches.title"),
+                                         AllIcons.Debugger.Watches, null);
+    watches.setCloseable(false);
+    watches.setAlertIcon(breakpointAlert);
+    myUi.addContent(watches, 0, PlaceInGrid.right, false);
+
+    // frames
+    Content framesContent = myUi.createContent(DebuggerContentInfo.FRAME_CONTENT, myFramesPanel, XDebuggerBundle.message("debugger.session.tab.frames.title"),
+                                               AllIcons.Debugger.Frame, myFramesPanel.getFramesList());
+    framesContent.setCloseable(false);
+    framesContent.setAlertIcon(breakpointAlert);
+
+    myUi.addContent(framesContent, 0, PlaceInGrid.left, false);
+
+    // variables
+    myVariablesPanel = new VariablesPanel(getProject(), myStateManager, this);
+    myVariablesPanel.getFrameTree().setAutoVariablesMode(debuggerSettings.AUTO_VARIABLES_MODE);
+    Content vars = myUi.createContent(DebuggerContentInfo.VARIABLES_CONTENT, myVariablesPanel, XDebuggerBundle.message("debugger.session.tab.variables.title"),
+                                      AllIcons.Debugger.Value, null);
+    vars.setCloseable(false);
+    vars.setAlertIcon(breakpointAlert);
+    myUi.addContent(vars, 0, PlaceInGrid.center, false);
+
+    // threads
+    myThreadsPanel = new ThreadsPanel(project, getContextManager());
+    Content threadsContent = myUi.createContent(DebuggerContentInfo.THREADS_CONTENT, myThreadsPanel, XDebuggerBundle.message("debugger.session.tab.threads.title"),
+                                                AllIcons.Debugger.Threads, null);
+    threadsContent.setCloseable(false);
+    //threadsContent.setAlertIcon(breakpointAlert);
+
+    //final DefaultActionGroup threadsGroup = new DefaultActionGroup();
+    //threadsContent.setActions(threadsGroup, ActionPlaces.DEBUGGER_TOOLBAR, threadsPanel.getThreadsTree());
+
+    myUi.addContent(threadsContent, 0, PlaceInGrid.left, true);
+
+    for (Content each : myUi.getContents()) {
+      updateStatus(each);
+    }
+
+    myUi.addListener(new ContentManagerAdapter() {
+      public void selectionChanged(ContentManagerEvent event) {
+        updateStatus(event.getContent());
+      }
+    }, this);
+  }
+
+  private static void updateStatus(final Content content) {
+    if (content.getComponent() instanceof DebuggerView) {
+      final DebuggerView view = (DebuggerView)content.getComponent();
+      if (content.isSelected()) {
+        view.setUpdateEnabled(true);
+        if (view.isRefreshNeeded()) {
+          view.rebuildIfVisible(DebuggerSession.EVENT_CONTEXT);
+        }
+      }
+      else {
+        view.setUpdateEnabled(false);
+      }
+    }
+  }
+
+  public MainWatchPanel getWatchPanel() {
+    return myWatchPanel;
+  }
+
+  @Override
+  public RunContentDescriptor getRunContentDescriptor() {
+    return myRunContentDescriptor;
+  }
+
+  private RunContentDescriptor initUI(ExecutionResult executionResult) {
+
+    myConsole = executionResult.getExecutionConsole();
+    myRunContentDescriptor = new RunContentDescriptor(myConsole, executionResult.getProcessHandler(), myUi.getComponent(), getSessionName(), myIcon);
+
+    if (ApplicationManager.getApplication().isUnitTestMode()) {
+      return myRunContentDescriptor;
+    }
+
+
+    myUi.removeContent(myUi.findContent(DebuggerContentInfo.CONSOLE_CONTENT), true);
+
+    Content console = null;
+    if (myConsole instanceof ExecutionConsoleEx) {
+      ((ExecutionConsoleEx)myConsole).buildUi(myUi);
+      console = myUi.findContent(DebuggerContentInfo.CONSOLE_CONTENT);
+      if (console == null) {
+        LOG.debug("Reuse console created with non-debug runner");
+      }
+    }
+    if (console == null) {
+      console = myUi.createContent(DebuggerContentInfo.CONSOLE_CONTENT, myConsole.getComponent(),
+                                           XDebuggerBundle.message("debugger.session.tab.console.content.name"),
+                                           AllIcons.Debugger.Console, myConsole.getPreferredFocusableComponent());
+
+      console.setCloseable(false);
+      myUi.addContent(console, 1, PlaceInGrid.bottom, false);
+    }
+    attachNotificationTo(console);
+
+    if (myConsole != null) {
+      Disposer.register(this, myConsole);
+    }
+
+    final DefaultActionGroup consoleActions = new DefaultActionGroup();
+    if (myConsole instanceof ConsoleView) {
+      AnAction[] actions = ((ConsoleView)myConsole).createConsoleActions();
+      for (AnAction goaction : actions) {
+        consoleActions.add(goaction);
+      }
+    }
+    console.setActions(consoleActions, ActionPlaces.DEBUGGER_TOOLBAR, myConsole.getPreferredFocusableComponent());
+
+    myDebugUIEnvironment.initLogs(myRunContentDescriptor, getLogManager());
+
+    DefaultActionGroup leftToolbar = new DefaultActionGroup();
+
+    if (executionResult instanceof DefaultExecutionResult) {
+      final AnAction[] actions = ((DefaultExecutionResult)executionResult).getRestartActions();
+      if (actions != null) {
+        leftToolbar.addAll(actions);
+        if (actions.length > 0) {
+          leftToolbar.addSeparator();
+        }
+      }
+    }
+    final AnAction[] profileActions = executionResult.getActions();
+    leftToolbar.addAll(profileActions);
+
+    leftToolbar.add(getCustomizedActionGroup(XDebuggerActions.TOOL_WINDOW_LEFT_TOOLBAR_GROUP));
+    if (executionResult instanceof DefaultExecutionResult) {
+      AnAction[] actions = ((DefaultExecutionResult)executionResult).getAdditionalStopActions();
+      for (AnAction action : actions) {
+        leftToolbar.add(action, new Constraints(Anchor.AFTER, IdeActions.ACTION_STOP_PROGRAM));
+      }
+    }
+
+    leftToolbar.addSeparator();
+    addAction(leftToolbar, DebuggerActions.EXPORT_THREADS);
+    addAction(leftToolbar, DebuggerActions.DUMP_THREADS);
+    leftToolbar.addSeparator();
+
+    leftToolbar.add(myUi.getOptions().getLayoutActions());
+
+    final AnAction[] commonSettings = myUi.getOptions().getSettingsActionsList();
+    final AnAction commonSettingsList = myUi.getOptions().getSettingsActions();
+
+    final DefaultActionGroup settings = new DefaultActionGroup("DebuggerSettings", true) {
+      @Override
+      public void update(AnActionEvent e) {
+        e.getPresentation().setText(ActionsBundle.message("group.XDebugger.settings.text"));
+        e.getPresentation().setIcon(commonSettingsList.getTemplatePresentation().getIcon());
+      }
+
+      @Override
+      public boolean isDumbAware() {
+        return true;
+      }
+    };
+    for (AnAction each : commonSettings) {
+      settings.add(each);
+    }
+    if (commonSettings.length > 0) {
+      settings.addSeparator();
+    }
+    settings.add(new WatchLastMethodReturnValueAction());
+    settings.add(new AutoVarsSwitchAction());
+    settings.addSeparator();
+    addActionToGroup(settings, XDebuggerActions.AUTO_TOOLTIP);
+
+    leftToolbar.add(settings);
+
+    leftToolbar.addSeparator();
+
+    addActionToGroup(leftToolbar, PinToolwindowTabAction.ACTION_NAME);
+
+    myDebugUIEnvironment.initActions(myRunContentDescriptor, leftToolbar);
+
+    myUi.getOptions().setLeftToolbar(leftToolbar, ActionPlaces.DEBUGGER_TOOLBAR);
+
+    return myRunContentDescriptor;
+  }
+
+  private static void addAction(DefaultActionGroup group, String actionId) {
+    group.add(ActionManager.getInstance().getAction(actionId));
+  }
+
+  private static void addActionToGroup(final DefaultActionGroup group, final String actionId) {
+    AnAction action = ActionManager.getInstance().getAction(actionId);
+    if (action != null) group.add(action);
+  }
+
+
+  public void dispose() {
+    disposeSession();
+    myFramesPanel.dispose();
+    myVariablesPanel.dispose();
+    myWatchPanel.dispose();
+    myThreadsPanel.dispose();
+    myConsole = null;
+    super.dispose();
+  }
+
+  private void disposeSession() {
+    final DebuggerSession session = myDebuggerSession;
+    myDebuggerSession = null;
+    if (session != null) {
+      session.dispose();
+    }
+  }
+
+  @Nullable
+  private DebugProcessImpl getDebugProcess() {
+    final DebuggerSession session = myDebuggerSession;
+    return session != null ? session.getProcess() : null;
+  }
+
+  public void reuse(DebuggerSessionTab reuseSession) {
+    DebuggerTreeNodeImpl[] watches = reuseSession.getWatchPanel().getWatchTree().getWatches();
+
+    final WatchDebuggerTree watchTree = getWatchPanel().getWatchTree();
+    for (DebuggerTreeNodeImpl watch : watches) {
+      watchTree.addWatch((WatchItemDescriptor)watch.getDescriptor());
+    }
+  }
+
+  public String getSessionName() {
+    return myDebugUIEnvironment.getEnvironment().getSessionName();
+  }
+
+  public DebuggerStateManager getContextManager() {
+    return myStateManager;
+  }
+
+  @Nullable
+  public TextWithImports getSelectedExpression() {
+    final DebuggerSession session = myDebuggerSession;
+    if (session == null || session.getState() != DebuggerSession.STATE_PAUSED) {
+      return null;
+    }
+    JTree tree = myVariablesPanel.getFrameTree();
+    if (tree == null || !tree.hasFocus()) {
+      tree = myWatchPanel.getWatchTree();
+      if (tree == null || !tree.hasFocus()) {
+        return null;
+      }
+    }
+    TreePath path = tree.getSelectionPath();
+    if (path == null) {
+      return null;
+    }
+    DebuggerTreeNodeImpl node = (DebuggerTreeNodeImpl)path.getLastPathComponent();
+    if (node == null) {
+      return null;
+    }
+    NodeDescriptorImpl descriptor = node.getDescriptor();
+    if (!(descriptor instanceof ValueDescriptorImpl)) {
+      return null;
+    }
+    if (descriptor instanceof WatchItemDescriptor) {
+      return ((WatchItemDescriptor)descriptor).getEvaluationText();
+    }
+    try {
+      return DebuggerTreeNodeExpression.createEvaluationText(node, getContextManager().getContext());
+    }
+    catch (EvaluateException e) {
+      return null;
+    }
+  }
+
+  @Nullable
+  @Override
+  protected RunProfile getRunProfile() {
+    return myDebugUIEnvironment != null ? myDebugUIEnvironment.getRunProfile() : null;
+  }
+
+  public RunContentDescriptor attachToSession(final DebuggerSession session, DebugUIEnvironment environment) throws ExecutionException {
+    disposeSession();
+    myDebuggerSession = session;
+    myDebugUIEnvironment = environment;
+
+    session.getContextManager().addListener(new DebuggerContextListener() {
+      public void changeEvent(DebuggerContextImpl newContext, int event) {
+        if (!myUi.isDisposed()) {
+          attractFramesOnPause(event);
+          myStateManager.fireStateChanged(newContext, event);
+          SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+              if (!myUi.isDisposed()) {
+                myUi.updateActionsNow();
+              }
+            }
+          });
+        }
+      }
+    });
+    return initUI(session.getProcess().getExecutionResult());
+  }
+
+  private void attractFramesOnPause(final int event) {
+    if (DebuggerSession.EVENT_PAUSE == event) {
+      myUi.attractBy(XDebuggerUIConstants.LAYOUT_VIEW_BREAKPOINT_CONDITION);
+    }
+    else if (DebuggerSession.EVENT_RESUME == event) {
+      myUi.clearAttractionBy(XDebuggerUIConstants.LAYOUT_VIEW_BREAKPOINT_CONDITION);
+    }
+  }
+
+  public DebuggerSession getSession() {
+    return myDebuggerSession;
+  }
+
+  public void showFramePanel() {
+    myUi.selectAndFocus(myUi.findContent(DebuggerContentInfo.FRAME_CONTENT), true, false);
+  }
+
+  private int myThreadDumpsCount = 0;
+  private int myCurrentThreadDumpId = 1;
+
+  public void addThreadDump(List<ThreadState> threads) {
+    final Project project = getProject();
+    final TextConsoleBuilder consoleBuilder = TextConsoleBuilderFactory.getInstance().createBuilder(project);
+    List<Filter> filters = ExceptionFilters.getFilters(myDebuggerSession.getSearchScope());
+    for (Filter filter : filters) {
+      consoleBuilder.addFilter(filter);
+    }
+    final ConsoleView consoleView = consoleBuilder.getConsole();
+    final DefaultActionGroup toolbarActions = new DefaultActionGroup();
+    consoleView.allowHeavyFilters();
+    final ThreadDumpPanel panel = new ThreadDumpPanel(project, consoleView, toolbarActions, threads);
+
+    final Icon icon = null;
+    final String id = createThreadDumpContentId();
+    final Content content = myUi.createContent(id, panel, id, icon, null);
+    content.setCloseable(true);
+    content.setDescription("Thread Dump");
+    myUi.addContent(content);
+    myUi.selectAndFocus(content, true, true);
+    myThreadDumpsCount += 1;
+    myCurrentThreadDumpId += 1;
+    Disposer.register(this, new Disposable() {
+      public void dispose() {
+        myUi.removeContent(content, true);
+      }
+    });
+    Disposer.register(content, new Disposable() {
+      public void dispose() {
+        myThreadDumpsCount -= 1;
+        if (myThreadDumpsCount == 0) {
+          myCurrentThreadDumpId = 1;
+        }
+      }
+    });
+    myUi.selectAndFocus(content, true, false);
+    if (threads.size() > 0) {
+      panel.selectStackFrame(0);
+    }
+  }
+
+  private String createThreadDumpContentId() {
+    return THREAD_DUMP_CONTENT_PREFIX + " #" + myCurrentThreadDumpId;
+  }
+
+  private class MyDebuggerStateManager extends DebuggerStateManager {
+    public void fireStateChanged(DebuggerContextImpl newContext, int event) {
+      super.fireStateChanged(newContext, event);
+    }
+
+    public DebuggerContextImpl getContext() {
+      final DebuggerSession session = myDebuggerSession;
+      return session != null ? session.getContextManager().getContext() : DebuggerContextImpl.EMPTY_CONTEXT;
+    }
+
+    public void setState(DebuggerContextImpl context, int state, int event, String description) {
+      final DebuggerSession session = myDebuggerSession;
+      if (session != null) {
+        session.getContextManager().setState(context, state, event, description);
+      }
+    }
+  }
+
+  private class AutoVarsSwitchAction extends ToggleAction {
+    private volatile boolean myAutoModeEnabled;
+    private static final String myAutoModeText = "Auto-Variables Mode";
+    private static final String myDefaultModeText = "All-Variables Mode";
+
+    public AutoVarsSwitchAction() {
+      super("", "", AllIcons.Debugger.AutoVariablesMode);
+      myAutoModeEnabled = DebuggerSettings.getInstance().AUTO_VARIABLES_MODE;
+    }
+
+    public void update(final AnActionEvent e) {
+      super.update(e);
+      final Presentation presentation = e.getPresentation();
+      final boolean autoModeEnabled = (Boolean)presentation.getClientProperty(SELECTED_PROPERTY);
+      presentation.setText(autoModeEnabled ? myDefaultModeText : myAutoModeText);
+    }
+
+    public boolean isSelected(AnActionEvent e) {
+      return myAutoModeEnabled;
+    }
+
+    public void setSelected(AnActionEvent e, boolean enabled) {
+      myAutoModeEnabled = enabled;
+      DebuggerSettings.getInstance().AUTO_VARIABLES_MODE = enabled;
+      myVariablesPanel.getFrameTree().setAutoVariablesMode(enabled);
+    }
+  }
+
+  private class WatchLastMethodReturnValueAction extends ToggleAction {
+    private volatile boolean myWatchesReturnValues;
+    private final String myTextEnable;
+    private final String myTextUnavailable;
+    private final String myMyTextDisable;
+
+    public WatchLastMethodReturnValueAction() {
+      super("", DebuggerBundle.message("action.watch.method.return.value.description"), null);
+      myWatchesReturnValues = DebuggerSettings.getInstance().WATCH_RETURN_VALUES;
+      myTextEnable = DebuggerBundle.message("action.watches.method.return.value.enable");
+      myMyTextDisable = DebuggerBundle.message("action.watches.method.return.value.disable");
+      myTextUnavailable = DebuggerBundle.message("action.watches.method.return.value.unavailable.reason");
+    }
+
+    public void update(final AnActionEvent e) {
+      super.update(e);
+      final Presentation presentation = e.getPresentation();
+      final boolean watchValues = (Boolean)presentation.getClientProperty(SELECTED_PROPERTY);
+      final DebugProcessImpl process = getDebugProcess();
+      final String actionText = watchValues ? myMyTextDisable : myTextEnable;
+      if (process != null && process.canGetMethodReturnValue()) {
+        presentation.setEnabled(true);
+        presentation.setText(actionText);
+      }
+      else {
+        presentation.setEnabled(false);
+        presentation.setText(process == null ? actionText : myTextUnavailable);
+      }
+    }
+
+    public boolean isSelected(AnActionEvent e) {
+      return myWatchesReturnValues;
+    }
+
+    public void setSelected(AnActionEvent e, boolean watch) {
+      myWatchesReturnValues = watch;
+      DebuggerSettings.getInstance().WATCH_RETURN_VALUES = watch;
+      final DebugProcessImpl process = getDebugProcess();
+      if (process != null) {
+        process.setWatchMethodReturnValuesEnabled(watch);
+      }
+    }
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerStatementEditor.java b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerStatementEditor.java
new file mode 100644
index 0000000..fb378f7
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerStatementEditor.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui;
+
+import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
+import com.intellij.debugger.engine.evaluation.CodeFragmentFactory;
+import com.intellij.debugger.engine.evaluation.CodeFragmentKind;
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.debugger.engine.evaluation.TextWithImportsImpl;
+import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.EditorFactory;
+import com.intellij.openapi.editor.ex.EditorEx;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
+import com.intellij.ui.EditorTextField;
+import org.jetbrains.annotations.NonNls;
+
+import javax.swing.*;
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+
+/**
+ * @author lex
+ */
+public class DebuggerStatementEditor extends DebuggerEditorImpl {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.DebuggerStatementEditor");
+
+  private final EditorTextField myEditor;
+
+  private int    myRecentIdx;
+
+  public DebuggerStatementEditor(Project project, PsiElement context, @NonNls String recentsId, final CodeFragmentFactory factory) {
+    super(project, context, recentsId, factory);
+    myRecentIdx = getRecentItemsCount();
+    final Document document = EditorFactory.getInstance().createDocument("");
+    myEditor = new EditorTextField(document, project, factory.getFileType(), false, false) {
+      protected EditorEx createEditor() {
+        EditorEx editor = super.createEditor();
+        editor.setVerticalScrollbarVisible(true);
+        editor.setHorizontalScrollbarVisible(true);
+        return editor;
+      }
+    };
+
+    setLayout(new BorderLayout());
+    add(addChooseFactoryLabel(myEditor, true));
+
+    DefaultActionGroup actionGroup = new DefaultActionGroup(null, false);
+    actionGroup.add(new ItemAction(IdeActions.ACTION_PREVIOUS_OCCURENCE, this){
+      public void actionPerformed(AnActionEvent e) {
+        LOG.assertTrue(myRecentIdx >= 0);
+        // since recents are stored in a stack, previous item is at currentIndex + 1
+        myRecentIdx += 1;
+        updateTextFromRecents();
+      }
+
+      public void update(AnActionEvent e) {
+        e.getPresentation().setEnabled(myRecentIdx < getRecentItemsCount());
+      }
+    });
+    actionGroup.add(new ItemAction(IdeActions.ACTION_NEXT_OCCURENCE, this){
+      public void actionPerformed(AnActionEvent e) {
+        if(LOG.isDebugEnabled()) {
+          LOG.assertTrue(myRecentIdx < getRecentItemsCount());
+        }
+        // since recents are stored in a stack, next item is at currentIndex - 1
+        myRecentIdx -= 1;
+        updateTextFromRecents();
+      }
+
+      public void update(AnActionEvent e) {
+        e.getPresentation().setEnabled(myRecentIdx > 0);
+      }
+    });
+
+    add(ActionManager.getInstance().createActionToolbar(ActionPlaces.COMBO_PAGER, actionGroup, false).getComponent(),
+        BorderLayout.EAST);
+
+    setText(new TextWithImportsImpl(CodeFragmentKind.CODE_BLOCK, ""));
+  }
+
+  private void updateTextFromRecents() {
+    List<TextWithImports> recents = getRecents();
+    LOG.assertTrue(myRecentIdx <= recents.size());
+    setText(myRecentIdx < recents.size() ? recents.get(myRecentIdx) : new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, ""));
+  }
+
+  private List<TextWithImports> getRecents() {
+    final LinkedList<TextWithImports> recents = DebuggerRecents.getInstance(getProject()).getRecents(getRecentsId());
+    final ArrayList<TextWithImports> reversed = new ArrayList<TextWithImports>(recents.size());
+    for (final ListIterator<TextWithImports> it = recents.listIterator(recents.size()); it.hasPrevious();) {
+      reversed.add(it.previous());
+    }
+    return reversed;
+  }
+
+  private int getRecentItemsCount() {
+    return DebuggerRecents.getInstance(getProject()).getRecents(getRecentsId()).size();
+  }
+
+  public JComponent getPreferredFocusedComponent() {
+    final Editor editor = myEditor.getEditor();
+    return editor != null? editor.getContentComponent() : myEditor;
+  }
+
+  public TextWithImports getText() {
+    return createItem(myEditor.getDocument(), getProject());
+  }
+
+  @Override
+  protected void doSetText(TextWithImports text) {
+    restoreFactory(text);
+    myEditor.setNewDocumentAndFileType(getCurrentFactory().getFileType(), createDocument(text));
+  }
+
+  @Override
+  protected void updateEditorUi() {
+    final Editor editor = myEditor.getEditor();
+    if (editor != null) {
+      DaemonCodeAnalyzer.getInstance(getProject()).updateVisibleHighlighters(editor);
+    }
+  }
+
+  public TextWithImports createText(String text, String importsString) {
+    return new TextWithImportsImpl(CodeFragmentKind.CODE_BLOCK, text, importsString, getCurrentFactory().getFileType());
+  }
+
+  private static abstract class ItemAction extends AnAction {
+    public ItemAction(String sourceActionName, JComponent component) {
+      copyFrom(ActionManager.getInstance().getAction(sourceActionName));
+      registerCustomShortcutSet(getShortcutSet(), component);
+    }
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerView.java b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerView.java
new file mode 100644
index 0000000..048980d
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerView.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui;
+
+public interface DebuggerView {
+
+  void setUpdateEnabled(boolean enabled);
+
+  boolean isRefreshNeeded();
+  void rebuildIfVisible(final int eventContext);
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/EditorEvaluationCommand.java b/java/debugger/impl/src/com/intellij/debugger/ui/EditorEvaluationCommand.java
new file mode 100644
index 0000000..414bdd3
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/EditorEvaluationCommand.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui;
+
+import com.intellij.codeInsight.hint.HintManager;
+import com.intellij.codeInsight.hint.HintManagerImpl;
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerInvocationUtil;
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.engine.events.DebuggerContextCommandImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.progress.ProcessCanceledException;
+import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Computable;
+import com.intellij.psi.PsiElement;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author lex
+ */
+public abstract class EditorEvaluationCommand<T> extends DebuggerContextCommandImpl {
+  protected final PsiElement myElement;
+  @Nullable private final Editor myEditor;
+  protected final ProgressIndicator myProgressIndicator;
+  private final DebuggerContextImpl myDebuggerContext;
+
+  public EditorEvaluationCommand(@Nullable Editor editor, PsiElement expression, DebuggerContextImpl context,
+                                 final ProgressIndicator indicator) {
+    super(context);
+    Project project = expression.getProject();
+    myProgressIndicator = indicator;
+    myEditor = editor;
+    myElement = expression;
+    myDebuggerContext = (DebuggerManagerEx.getInstanceEx(project)).getContext();
+  }
+
+  public Priority getPriority() {
+    return Priority.HIGH;
+  }
+
+  protected abstract T evaluate(EvaluationContextImpl evaluationContext) throws EvaluateException;
+
+  public T evaluate() throws EvaluateException {
+    myProgressIndicator.setText(DebuggerBundle.message("progress.evaluating", ApplicationManager.getApplication().runReadAction(new Computable<String>() {
+            public String compute() {
+              return myElement.getText();
+            }
+          })));
+
+    try {
+      T result = evaluate(myDebuggerContext.createEvaluationContext());
+
+      if (myProgressIndicator.isCanceled()) throw new ProcessCanceledException();
+
+      return result;
+    } catch (final EvaluateException e) {
+      if (myEditor != null) {
+        DebuggerInvocationUtil.invokeLater(myDebuggerContext.getProject(), new Runnable() {
+          public void run() {
+            showEvaluationHint(myEditor, myElement, e);
+          }
+        }, myProgressIndicator.getModalityState());
+      }
+      throw e;
+    }
+  }
+
+  public static void showEvaluationHint(final Editor myEditor, final PsiElement myElement, final EvaluateException e) {
+    if (myEditor.isDisposed() || !myEditor.getComponent().isVisible()) return;
+
+    HintManager.getInstance().showErrorHint(myEditor, e.getMessage(), myElement.getTextRange().getStartOffset(),
+                                            myElement.getTextRange().getEndOffset(), HintManagerImpl.UNDER,
+                                            HintManagerImpl.HIDE_BY_ESCAPE | HintManagerImpl.HIDE_BY_TEXT_CHANGE,
+                                            1500);
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/EvaluationDialog.java b/java/debugger/impl/src/com/intellij/debugger/ui/EvaluationDialog.java
new file mode 100644
index 0000000..4730f94
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/EvaluationDialog.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui;
+
+import com.intellij.CommonBundle;
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.actions.DebuggerActions;
+import com.intellij.debugger.engine.evaluation.CodeFragmentFactory;
+import com.intellij.debugger.engine.evaluation.DefaultCodeFragmentFactory;
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerContextListener;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.debugger.impl.PositionUtil;
+import com.intellij.debugger.ui.impl.WatchDebuggerTree;
+import com.intellij.debugger.ui.impl.WatchPanel;
+import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
+import com.intellij.debugger.ui.impl.watch.EvaluationDescriptor;
+import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.psi.PsiElement;
+import com.intellij.xdebugger.XDebuggerBundle;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import javax.swing.tree.TreeModel;
+import java.awt.event.KeyEvent;
+import java.util.ArrayList;
+import java.util.List;
+
+public abstract class EvaluationDialog extends DialogWrapper {
+  private final MyEvaluationPanel myEvaluationPanel;
+  private final Project myProject;
+  private final DebuggerContextListener myContextListener;
+  private final DebuggerEditorImpl myEditor;
+  private final List<Runnable> myDisposeRunnables = new ArrayList<Runnable>();
+
+  public EvaluationDialog(Project project, TextWithImports text) {
+    super(project, true);
+    myProject = project;
+    setModal(false);
+    setCancelButtonText(CommonBundle.message("button.close"));
+    setOKButtonText(DebuggerBundle.message("button.evaluate"));
+
+    myEvaluationPanel = new MyEvaluationPanel(myProject);
+
+    myEditor = createEditor(DefaultCodeFragmentFactory.getInstance());
+
+    setDebuggerContext(getDebuggerContext());
+    initDialogData(text);
+
+    myContextListener = new DebuggerContextListener() {
+      public void changeEvent(DebuggerContextImpl newContext, int event) {
+        boolean close = true;
+        for (DebuggerSession session : DebuggerManagerEx.getInstanceEx(myProject).getSessions()) {
+          if (!session.isStopped()) {
+            close = false;
+            break;
+          }
+        }
+
+        if(close) {
+          close(CANCEL_EXIT_CODE);
+        }
+        else {
+          setDebuggerContext(newContext);
+        }
+      }
+    };
+    DebuggerManagerEx.getInstanceEx(myProject).getContextManager().addListener(myContextListener);
+
+    setHorizontalStretch(1f);
+    setVerticalStretch(1f);
+  }
+
+  protected void doOKAction() {
+    if (isOKActionEnabled()) {
+      doEvaluate();
+    }
+  }
+
+  protected void doEvaluate() {
+    if (myEditor == null || myEvaluationPanel == null) {
+      return;
+    }
+
+    myEvaluationPanel.clear();
+    TextWithImports codeToEvaluate = getCodeToEvaluate();
+    if (codeToEvaluate == null) {
+      return;
+    }
+    try {
+      setOKActionEnabled(false);
+      NodeDescriptorImpl descriptor = myEvaluationPanel.getWatchTree().addWatch(codeToEvaluate, "result").getDescriptor();
+      if (descriptor instanceof EvaluationDescriptor) {
+        final EvaluationDescriptor evalDescriptor = (EvaluationDescriptor)descriptor;
+        evalDescriptor.setCodeFragmentFactory(myEditor.getCurrentFactory());
+      }
+      myEvaluationPanel.getWatchTree().rebuild(getDebuggerContext());
+      descriptor.myIsExpanded = true;
+    }
+    finally {
+      setOKActionEnabled(true);
+    }
+    getEditor().addRecent(getCodeToEvaluate());
+
+    myEvaluationPanel.getContextManager().getContext().getDebuggerSession().refresh(true);
+  }
+
+  @Nullable
+  protected TextWithImports getCodeToEvaluate() {
+    TextWithImports text = getEditor().getText();
+    String s = text.getText();
+    if (s != null) {
+      s = s.trim();
+    }
+    if ("".equals(s)) {
+      return null;
+    }
+    return text;
+  }
+
+  public JComponent getPreferredFocusedComponent() {
+    return myEditor.getPreferredFocusedComponent();
+  }
+
+  protected String getDimensionServiceKey() {
+    return "#com.intellij.debugger.ui.EvaluationDialog2";
+  }
+
+  protected void addDisposeRunnable (Runnable runnable) {
+    myDisposeRunnables.add(runnable);
+  }
+
+  public void dispose() {
+    for (Runnable runnable : myDisposeRunnables) {
+      runnable.run();
+    }
+    myDisposeRunnables.clear();
+    myEditor.dispose();
+    DebuggerManagerEx.getInstanceEx(myProject).getContextManager().removeListener(myContextListener);
+    myEvaluationPanel.dispose();
+    super.dispose();
+  }
+
+  protected class MyEvaluationPanel extends WatchPanel {
+    public MyEvaluationPanel(final Project project) {
+      super(project, (DebuggerManagerEx.getInstanceEx(project)).getContextManager());
+      final WatchDebuggerTree watchTree = getWatchTree();
+      final AnAction setValueAction  = ActionManager.getInstance().getAction(DebuggerActions.SET_VALUE);
+      setValueAction.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0)), watchTree);
+      registerDisposable(new Disposable() {
+        public void dispose() {
+          setValueAction.unregisterCustomShortcutSet(watchTree);
+        }
+      });
+      setUpdateEnabled(true);
+      getTree().getEmptyText().setText(XDebuggerBundle.message("debugger.no.results"));
+    }
+
+    protected ActionPopupMenu createPopupMenu() {
+      ActionGroup group = (ActionGroup)ActionManager.getInstance().getAction(DebuggerActions.EVALUATION_DIALOG_POPUP);
+      return ActionManager.getInstance().createActionPopupMenu(DebuggerActions.EVALUATION_DIALOG_POPUP, group);
+    }
+
+    protected void changeEvent(DebuggerContextImpl newContext, int event) {
+      if (event == DebuggerSession.EVENT_REFRESH || event == DebuggerSession.EVENT_REFRESH_VIEWS_ONLY) {
+        // in order not to spoil the evaluation result do not re-evaluate the tree
+        final TreeModel treeModel = getTree().getModel();
+        updateTree(treeModel, (DebuggerTreeNodeImpl)treeModel.getRoot());
+      }
+    }
+
+    private void updateTree(final TreeModel model, final DebuggerTreeNodeImpl node) {
+      if (node == null) {
+        return;
+      }
+      if (node.getDescriptor().myIsExpanded) {
+        final int count = model.getChildCount(node);
+        for (int idx = 0; idx < count; idx++) {
+          final DebuggerTreeNodeImpl child = (DebuggerTreeNodeImpl)model.getChild(node, idx);
+          updateTree(model, child);
+        }
+      }
+      node.labelChanged();
+    }
+  }
+
+  protected void setDebuggerContext(DebuggerContextImpl context) {
+    final PsiElement contextElement = PositionUtil.getContextElement(context);
+    myEditor.setContext(contextElement);
+  }
+
+  protected PsiElement getContext() {
+    return myEditor.getContext();
+  }
+
+  protected void initDialogData(TextWithImports text) {
+    getEditor().setText(text);
+    myEvaluationPanel.clear();
+  }
+
+  public DebuggerContextImpl getDebuggerContext() {
+    return DebuggerManagerEx.getInstanceEx(myProject).getContext();
+  }
+
+  public DebuggerEditorImpl getEditor() {
+    return myEditor;
+  }
+
+  protected abstract DebuggerEditorImpl createEditor(final CodeFragmentFactory factory);
+
+  protected MyEvaluationPanel getEvaluationPanel() {
+    return myEvaluationPanel;
+  }
+
+  public Project getProject() {
+    return myProject;
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/EvaluatorRunnable.java b/java/debugger/impl/src/com/intellij/debugger/ui/EvaluatorRunnable.java
new file mode 100644
index 0000000..dda9fbb
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/EvaluatorRunnable.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: lex
+ * Date: May 28, 2003
+ * Time: 1:59:27 PM
+ * To change this template use Options | File Templates.
+ */
+public interface EvaluatorRunnable extends Runnable{
+  Object getValue();
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/ExportDialog.java b/java/debugger/impl/src/com/intellij/debugger/ui/ExportDialog.java
new file mode 100644
index 0000000..535853d
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/ExportDialog.java
@@ -0,0 +1,283 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/**
+ * created at Dec 14, 2001
+ * @author Jeka
+ */
+package com.intellij.debugger.ui;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerInvocationUtil;
+import com.intellij.debugger.HelpID;
+import com.intellij.debugger.actions.ThreadDumpAction;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.events.DebuggerCommandImpl;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
+import com.intellij.debugger.ui.impl.watch.MessageDescriptor;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.ModalityState;
+import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
+import com.intellij.openapi.help.HelpManager;
+import com.intellij.openapi.ide.CopyPasteManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.openapi.ui.Messages;
+import com.intellij.openapi.ui.TextFieldWithBrowseButton;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.ui.ScrollPaneFactory;
+import com.sun.jdi.*;
+import org.jetbrains.annotations.NonNls;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.datatransfer.StringSelection;
+import java.awt.event.ActionEvent;
+import java.io.File;
+import java.util.List;
+
+public class ExportDialog extends DialogWrapper {
+  private final JTextArea myTextArea = new JTextArea();
+  private TextFieldWithBrowseButton myTfFilePath;
+  private final Project myProject;
+  private final DebugProcessImpl myDebugProcess;
+  private final CopyToClipboardAction myCopyToClipboardAction = new CopyToClipboardAction();
+  private static final @NonNls String DEFAULT_REPORT_FILE_NAME = "threads_report.txt";
+
+  public ExportDialog(DebugProcessImpl debugProcess, String destinationDirectory) {
+    super(debugProcess.getProject(), true);
+    myDebugProcess = debugProcess;
+    myProject = debugProcess.getProject();
+    setTitle(DebuggerBundle.message("threads.export.dialog.title"));
+    setOKButtonText(DebuggerBundle.message("button.save"));
+
+    init();
+
+    setOKActionEnabled(false);
+    myCopyToClipboardAction.setEnabled(false);
+
+    myTextArea.setText(MessageDescriptor.EVALUATING.getLabel());
+    debugProcess.getManagerThread().invoke(new ExportThreadsCommand(ApplicationManager.getApplication().getModalityStateForComponent(myTextArea)));
+
+    myTfFilePath.setText(destinationDirectory + File.separator + DEFAULT_REPORT_FILE_NAME);
+    setHorizontalStretch(1.5f);
+  }
+
+  protected Action[] createActions(){
+    return new Action[]{getOKAction(), myCopyToClipboardAction, getCancelAction(), getHelpAction()};
+  }
+
+  protected void doHelpAction() {
+    HelpManager.getInstance().invokeHelp(HelpID.EXPORT_THREADS);
+  }
+
+  protected JComponent createNorthPanel() {
+    JPanel box = new JPanel(new BorderLayout());
+    box.add(new JLabel(DebuggerBundle.message("label.threads.export.dialog.file")), BorderLayout.WEST);
+    myTfFilePath = new TextFieldWithBrowseButton();
+    myTfFilePath.addBrowseFolderListener(null, null, myProject, FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor());
+    box.add(myTfFilePath, BorderLayout.CENTER);
+    JPanel panel = new JPanel(new BorderLayout());
+    panel.add(box, BorderLayout.CENTER);
+    panel.add(Box.createVerticalStrut(7), BorderLayout.SOUTH);
+    return panel;
+  }
+
+  protected JComponent createCenterPanel() {
+    myTextArea.setEditable(false);
+    JScrollPane pane = ScrollPaneFactory.createScrollPane(myTextArea);
+    pane.setPreferredSize(new Dimension(400, 300));
+    return pane;
+  }
+
+  protected void doOKAction() {
+    String path = myTfFilePath.getText();
+    File file = new File(path);
+    if (file.isDirectory()) {
+      Messages.showMessageDialog(
+        myProject,
+        DebuggerBundle.message("error.threads.export.dialog.file.is.directory"),
+        DebuggerBundle.message("threads.export.dialog.title"),
+        Messages.getErrorIcon()
+      );
+    }
+    else if (file.exists()) {
+      int answer = Messages.showYesNoDialog(
+        myProject,
+        DebuggerBundle.message("error.threads.export.dialog.file.already.exists", path),
+        DebuggerBundle.message("threads.export.dialog.title"),
+        Messages.getQuestionIcon()
+      );
+      if (answer == 0) {
+        super.doOKAction();
+      }
+    }
+    else {
+      super.doOKAction();
+    }
+  }
+
+  public String getFilePath() {
+    return myTfFilePath.getText();
+  }
+
+  public String getTextToSave() {
+    return myTextArea.getText();
+  }
+
+  protected String getDimensionServiceKey(){
+    return "#com.intellij.debugger.ui.ExportDialog";
+  }
+
+  public static String getExportThreadsText(VirtualMachineProxyImpl vmProxy) {
+    final StringBuffer buffer = new StringBuffer(512);
+    List<ThreadReference> threads = vmProxy.getVirtualMachine().allThreads();
+    for (ThreadReference threadReference : threads) {
+      final String name = threadName(threadReference);
+      if (name == null) {
+        continue;
+      }
+      buffer.append(name);
+      ReferenceType referenceType = threadReference.referenceType();
+      if (referenceType != null) {
+        //noinspection HardCodedStringLiteral
+        Field daemon = referenceType.fieldByName("daemon");
+        if (daemon != null) {
+          Value value = threadReference.getValue(daemon);
+          if (value instanceof BooleanValue && ((BooleanValue)value).booleanValue()) {
+            buffer.append(" ").append(DebuggerBundle.message("threads.export.attribute.label.daemon"));
+          }
+        }
+
+        //noinspection HardCodedStringLiteral
+        Field priority = referenceType.fieldByName("priority");
+        if (priority != null) {
+          Value value = threadReference.getValue(priority);
+          if (value instanceof IntegerValue) {
+            buffer.append(", ").append(DebuggerBundle.message("threads.export.attribute.label.priority", ((IntegerValue)value).intValue()));
+          }
+        }
+      }
+
+      ThreadGroupReference groupReference = threadReference.threadGroup();
+      if (groupReference != null) {
+        buffer.append(", ").append(DebuggerBundle.message("threads.export.attribute.label.group", groupReference.name()));
+      }
+      buffer.append(", ").append(
+        DebuggerBundle.message("threads.export.attribute.label.status", DebuggerUtilsEx.getThreadStatusText(threadReference.status())));
+
+      try {
+        if (vmProxy.canGetOwnedMonitorInfo() && vmProxy.canGetMonitorInfo()) {
+          List<ObjectReference> list = threadReference.ownedMonitors();
+          for (ObjectReference reference : list) {
+            final List<ThreadReference> waiting = reference.waitingThreads();
+            for (ThreadReference thread : waiting) {
+              final String waitingThreadName = threadName(thread);
+              if (waitingThreadName != null) {
+                buffer.append("\n\t ").append(DebuggerBundle.message("threads.export.attribute.label.blocks.thread", waitingThreadName));
+              }
+            }
+          }
+        }
+
+        ObjectReference waitedMonitor = vmProxy.canGetCurrentContendedMonitor() ? threadReference.currentContendedMonitor() : null;
+        if (waitedMonitor != null) {
+          if (vmProxy.canGetMonitorInfo()) {
+            ThreadReference waitedThread = waitedMonitor.owningThread();
+            if (waitedThread != null) {
+              final String waitedThreadName = threadName(waitedThread);
+              if (waitedThreadName != null) {
+                buffer.append("\n\t ").append(DebuggerBundle.message("threads.export.attribute.label.waiting.for.thread", waitedThreadName,
+                                                                     ThreadDumpAction.renderObject(waitedMonitor)));
+              }
+            }
+          }
+        }
+
+        final List<StackFrame> frames = threadReference.frames();
+        for (StackFrame stackFrame : frames) {
+          final Location location = stackFrame.location();
+          buffer.append("\n\t  ").append(renderLocation(location));
+        }
+      }
+      catch (IncompatibleThreadStateException e) {
+        buffer.append("\n\t ").append(DebuggerBundle.message("threads.export.attribute.error.incompatible.state"));
+      }
+      buffer.append("\n\n");
+    }
+    return buffer.toString();
+  }
+
+  private static String renderLocation(final Location location) {
+    String sourceName;
+    try {
+      sourceName = location.sourceName();
+    }
+    catch (AbsentInformationException e) {
+      sourceName = "Unknown Source";
+    }
+    return DebuggerBundle.message(
+        "export.threads.stackframe.format",
+        location.declaringType().name() + "." + location.method().name(), 
+        sourceName, 
+        location.lineNumber()
+    );
+  }
+
+  private static String threadName(ThreadReference threadReference) {
+    try {
+      return threadReference.name() + "@" + threadReference.uniqueID();
+    }
+    catch (ObjectCollectedException e) {
+      return null;
+    }
+  }
+
+  private class CopyToClipboardAction extends AbstractAction {
+    public CopyToClipboardAction() {
+      super(DebuggerBundle.message("button.copy"));
+      putValue(Action.SHORT_DESCRIPTION, DebuggerBundle.message("export.dialog.copy.action.description"));
+    }
+
+    public void actionPerformed(ActionEvent e) {
+      String s = StringUtil.convertLineSeparators(myTextArea.getText());
+      CopyPasteManager.getInstance().setContents(new StringSelection(s));
+    }
+  }
+
+  private class ExportThreadsCommand extends DebuggerCommandImpl {
+    protected ModalityState myModalityState;
+
+    public ExportThreadsCommand(ModalityState modalityState) {
+      myModalityState = modalityState;
+    }
+
+    private void setText(final String text) {
+      DebuggerInvocationUtil.invokeLater(myProject, new Runnable() {
+          public void run() {
+            myTextArea.setText(text);
+            setOKActionEnabled(true);
+            myCopyToClipboardAction.setEnabled(true);
+          }
+        }, myModalityState);
+    }
+
+    protected void action() {
+      setText(getExportThreadsText(myDebugProcess.getVirtualMachineProxy()));
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/ExpressionEvaluationDialog.java b/java/debugger/impl/src/com/intellij/debugger/ui/ExpressionEvaluationDialog.java
new file mode 100644
index 0000000..38bff61
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/ExpressionEvaluationDialog.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerInvocationUtil;
+import com.intellij.debugger.HelpID;
+import com.intellij.debugger.actions.EvaluateActionHandler;
+import com.intellij.debugger.engine.evaluation.CodeFragmentFactory;
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.debugger.impl.PositionUtil;
+import com.intellij.debugger.settings.DebuggerSettings;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.CustomShortcutSet;
+import com.intellij.openapi.help.HelpManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.ui.IdeBorderFactory;
+import com.intellij.ui.components.JBLabel;
+import com.intellij.util.ui.UIUtil;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+
+public class ExpressionEvaluationDialog extends EvaluationDialog {
+
+  public ExpressionEvaluationDialog(Project project, TextWithImports defaultExpression) {
+    super(project, defaultExpression);
+    setTitle(DebuggerBundle.message("evaluate.expression.dialog.title"));
+
+    final KeyStroke expressionStroke = KeyStroke.getKeyStroke(KeyEvent.VK_E, KeyEvent.ALT_MASK);
+    final KeyStroke resultStroke = KeyStroke.getKeyStroke(KeyEvent.VK_R, KeyEvent.ALT_MASK);
+
+    final JRootPane rootPane = getRootPane();
+
+    final AnAction anAction = new AnAction() {
+      public void actionPerformed(AnActionEvent e) {
+        getExpressionCombo().requestFocus();
+      }
+    };
+    anAction.registerCustomShortcutSet(new CustomShortcutSet(expressionStroke), rootPane);
+    addDisposeRunnable(new Runnable() {
+      public void run() {
+        anAction.unregisterCustomShortcutSet(rootPane);
+      }
+    });
+
+    final AnAction anAction2 = new AnAction() {
+      public void actionPerformed(AnActionEvent e) {
+        getEvaluationPanel().getWatchTree().requestFocus();
+      }
+    };
+    anAction2.registerCustomShortcutSet(new CustomShortcutSet(resultStroke), rootPane);
+    addDisposeRunnable(new Runnable() {
+      public void run() {
+        anAction2.unregisterCustomShortcutSet(rootPane);
+      }
+    });
+
+    init();
+  }
+
+  protected DebuggerExpressionComboBox createEditor(final CodeFragmentFactory factory) {
+    return new DebuggerExpressionComboBox(getProject(), PositionUtil.getContextElement(getDebuggerContext()), "evaluation", factory);
+  }
+
+  protected JComponent createCenterPanel() {
+    final JPanel panel = new JPanel(new BorderLayout());
+
+    final JPanel exprPanel = new JPanel(new BorderLayout(UIUtil.DEFAULT_HGAP, 0));
+    exprPanel.add(new JLabel(DebuggerBundle.message("label.evaluate.dialog.expression")), BorderLayout.WEST);
+    exprPanel.add(getExpressionCombo(), BorderLayout.CENTER);
+    final JBLabel help = new JBLabel("Press Enter to Evaluate or Control+Enter to evaluate and add to the Watches", SwingConstants.RIGHT);
+    help.setBorder(IdeBorderFactory.createEmptyBorder(2,0,6,0));
+    help.setComponentStyle(UIUtil.ComponentStyle.SMALL);
+    help.setFontColor(UIUtil.FontColor.BRIGHTER);
+    exprPanel.add(help, BorderLayout.SOUTH);
+
+
+    final JPanel resultPanel = new JPanel(new BorderLayout());
+    //resultPanel.add(new JLabel(DebuggerBundle.message("label.evaluate.dialog.result")), BorderLayout.NORTH);
+    resultPanel.add(getEvaluationPanel(), BorderLayout.CENTER);
+
+    panel.add(exprPanel, BorderLayout.NORTH);
+    panel.add(resultPanel, BorderLayout.CENTER);
+
+    return panel;
+  }
+
+  protected void initDialogData(TextWithImports text) {
+    super.initDialogData(text);
+    getExpressionCombo().selectAll();
+  }
+
+  private DebuggerExpressionComboBox getExpressionCombo() {
+    return (DebuggerExpressionComboBox)getEditor();
+  }
+
+  protected Action[] createActions() {
+    return new Action[] { getOKAction(), getCancelAction(), new SwitchAction(), getHelpAction() } ;
+  }
+
+  @Override
+  protected void createDefaultActions() {
+    super.createDefaultActions();
+    myOKAction = new OkAction(){
+      @Override
+      public void actionPerformed(ActionEvent e) {
+        super.actionPerformed(e);
+        if ((e.getModifiers() & InputEvent.CTRL_MASK) != 0) {
+          addCurrentExpressionToWatches();
+        }
+      }
+    };
+  }
+
+  private void addCurrentExpressionToWatches() {
+    final DebuggerSessionTab tab = DebuggerPanelsManager.getInstance(getProject()).getSessionTab();
+    if (tab != null) {
+      final TextWithImports evaluate = getCodeToEvaluate();
+      if (evaluate != null) {
+        tab.getWatchPanel().getWatchTree().addWatch(evaluate, null);
+      }
+    }
+  }
+
+  protected void doHelpAction() {
+    HelpManager.getInstance().invokeHelp(HelpID.EVALUATE);
+  }
+
+  private class SwitchAction extends AbstractAction {
+    public SwitchAction() {
+      putValue(Action.NAME, DebuggerBundle.message("action.evaluate.expression.dialog.switch.mode.description"));
+    }
+
+    public void actionPerformed(ActionEvent e) {
+      final TextWithImports text = getEditor().getText();
+      doCancelAction();
+      DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
+        public void run() {
+          EvaluateActionHandler.showEvaluationDialog(getProject(), text, DebuggerSettings.EVALUATE_FRAGMENT);
+        }
+      });
+    }
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/FramesPanel.java b/java/debugger/impl/src/com/intellij/debugger/ui/FramesPanel.java
new file mode 100644
index 0000000..1a137e9
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/FramesPanel.java
@@ -0,0 +1,691 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerInvocationUtil;
+import com.intellij.debugger.actions.DebuggerActions;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
+import com.intellij.debugger.engine.SuspendContextImpl;
+import com.intellij.debugger.engine.SuspendManagerUtil;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.engine.events.DebuggerContextCommandImpl;
+import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
+import com.intellij.debugger.engine.jdi.StackFrameProxy;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerContextUtil;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.debugger.impl.DebuggerStateManager;
+import com.intellij.debugger.jdi.StackFrameProxyImpl;
+import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
+import com.intellij.debugger.settings.DebuggerSettings;
+import com.intellij.debugger.ui.impl.DebuggerComboBoxRenderer;
+import com.intellij.debugger.ui.impl.FramesList;
+import com.intellij.debugger.ui.impl.UpdatableDebuggerView;
+import com.intellij.debugger.ui.impl.watch.MethodsTracker;
+import com.intellij.debugger.ui.impl.watch.StackFrameDescriptorImpl;
+import com.intellij.debugger.ui.impl.watch.ThreadDescriptorImpl;
+import com.intellij.debugger.ui.tree.render.DescriptorLabelListener;
+import com.intellij.icons.AllIcons;
+import com.intellij.ide.CommonActionsManager;
+import com.intellij.ide.OccurenceNavigator;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.actionSystem.impl.ActionToolbarImpl;
+import com.intellij.openapi.application.ModalityState;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.ComboBoxWithWidePopup;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.ui.CaptionPanel;
+import com.intellij.ui.PopupHandler;
+import com.intellij.ui.ScrollPaneFactory;
+import com.intellij.ui.border.CustomLineBorder;
+import com.intellij.ui.components.panels.Wrapper;
+import com.intellij.util.Alarm;
+import com.sun.jdi.ObjectCollectedException;
+import com.sun.jdi.VMDisconnectedException;
+
+import javax.swing.*;
+import javax.swing.border.EmptyBorder;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import java.awt.*;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+
+public class FramesPanel extends UpdatableDebuggerView {
+  private static final Icon FILTER_STACK_FRAMES_ICON = AllIcons.Debugger.Class_filter;
+
+  private final JComboBox myThreadsCombo;
+  private final FramesList myFramesList;
+  private final ThreadsListener myThreadsListener;
+  private final FramesListener myFramesListener;
+  private final DebuggerStateManager myStateManager;
+  private boolean myShowLibraryFrames = DebuggerSettings.getInstance().SHOW_LIBRARY_STACKFRAMES;
+  private final Alarm myRebuildAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD);
+
+  public FramesPanel(Project project, DebuggerStateManager stateManager) {
+    super(project, stateManager);
+    myStateManager = stateManager;
+
+    setLayout(new BorderLayout());
+
+    myThreadsCombo = new ComboBoxWithWidePopup();
+    myThreadsCombo.setRenderer(new DebuggerComboBoxRenderer(myThreadsCombo.getRenderer()));
+    myThreadsListener = new ThreadsListener();
+    myThreadsCombo.addItemListener(myThreadsListener);
+
+    myFramesList = new FramesList(project);
+    myFramesListener = new FramesListener();
+    myFramesList.addListSelectionListener(myFramesListener);
+
+    myFramesList.addMouseListener(new MouseAdapter() {
+      public void mousePressed(final MouseEvent e) {
+        int index = myFramesList.locationToIndex(e.getPoint());
+        if (index >= 0 && myFramesList.isSelectedIndex(index)) {
+          processListValue(myFramesList.getModel().getElementAt(index));
+        }
+      }
+    });
+
+    registerThreadsPopupMenu(myFramesList);
+
+    setBorder(null);
+
+    final ActionToolbar toolbar = createToolbar();
+    Wrapper threads = new Wrapper();
+    CustomLineBorder border = new CustomLineBorder(CaptionPanel.CNT_ACTIVE_BORDER_COLOR, 0, 0, 1, 0);
+    threads.setBorder(border);
+    threads.add(toolbar.getComponent(), BorderLayout.EAST);
+    threads.add(myThreadsCombo, BorderLayout.CENTER);
+    add(threads, BorderLayout.NORTH);
+    add(ScrollPaneFactory.createScrollPane(myFramesList), BorderLayout.CENTER);
+  }
+
+  private ActionToolbar createToolbar() {
+    final DefaultActionGroup framesGroup = new DefaultActionGroup();
+    framesGroup.addSeparator();
+
+    CommonActionsManager actionsManager = CommonActionsManager.getInstance();
+    framesGroup.add(actionsManager.createPrevOccurenceAction(getOccurenceNavigator()));
+    framesGroup.add(actionsManager.createNextOccurenceAction(getOccurenceNavigator()));
+    framesGroup.add(new ShowLibraryFramesAction());
+
+    final ActionToolbar toolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.DEBUGGER_TOOLBAR, framesGroup, true);
+    toolbar.setReservePlaceAutoPopupIcon(false);
+    ((ActionToolbarImpl)toolbar).setAddSeparatorFirst(true);
+    toolbar.getComponent().setBorder(new EmptyBorder(1, 0, 0, 0));
+    return toolbar;
+  }
+
+  public DebuggerStateManager getContextManager() {
+    return myStateManager;
+  }
+
+  private class FramesListener implements ListSelectionListener {
+    boolean myIsEnabled = true;
+
+    public void setEnabled(boolean enabled) {
+      myIsEnabled = enabled;
+    }
+
+    public void valueChanged(ListSelectionEvent e) {
+      if (!myIsEnabled || e.getValueIsAdjusting()) {
+        return;
+      }
+      final JList list = (JList)e.getSource();
+      processListValue(list.getSelectedValue());
+    }
+
+  }
+  private void processListValue(final Object selected) {
+    if (selected instanceof StackFrameDescriptorImpl) {
+      DebuggerContextUtil.setStackFrame(getContextManager(), ((StackFrameDescriptorImpl)selected).getFrameProxy());
+    }
+  }
+
+
+  private void registerThreadsPopupMenu(final JList framesList) {
+    final PopupHandler popupHandler = new PopupHandler() {
+      public void invokePopup(Component comp, int x, int y) {
+        DefaultActionGroup group = (DefaultActionGroup)ActionManager.getInstance().getAction(DebuggerActions.THREADS_PANEL_POPUP);
+        ActionPopupMenu popupMenu = ActionManager.getInstance().createActionPopupMenu(DebuggerActions.THREADS_PANEL_POPUP, group);
+        popupMenu.getComponent().show(comp, x, y);
+      }
+    };
+    framesList.addMouseListener(popupHandler);
+    registerDisposable(new Disposable() {
+      public void dispose() {
+        myThreadsCombo.removeItemListener(myThreadsListener);
+        framesList.removeMouseListener(popupHandler);
+      }
+    });
+  }
+
+  private class ThreadsListener implements ItemListener {
+    boolean myIsEnabled = true;
+
+    public void setEnabled(boolean enabled) {
+      myIsEnabled = enabled;
+    }
+
+    public void itemStateChanged(ItemEvent e) {
+      if (!myIsEnabled) return;
+      if (e.getStateChange() == ItemEvent.SELECTED) {
+        ThreadDescriptorImpl item = (ThreadDescriptorImpl)e.getItem();
+        DebuggerContextUtil.setThread(getContextManager(), item);
+      }
+    }
+  }
+
+  private final AtomicBoolean myPerformFullRebuild = new AtomicBoolean(false);
+
+  protected void rebuild(int event) {
+    myRebuildAlarm.cancelAllRequests();
+    final boolean isRefresh = event == DebuggerSession.EVENT_REFRESH ||
+                              event == DebuggerSession.EVENT_REFRESH_VIEWS_ONLY ||
+                              event == DebuggerSession.EVENT_THREADS_REFRESH;
+    if (!isRefresh) {
+      myPerformFullRebuild.set(true);
+    }
+    myRebuildAlarm.addRequest(new Runnable() {
+      public void run() {
+        try {
+          doRebuild(!myPerformFullRebuild.getAndSet(false));
+        }
+        catch (VMDisconnectedException e) {
+          // ignored
+        }
+      }
+    }, 100, ModalityState.NON_MODAL);
+  }
+
+  private void doRebuild(boolean refreshOnly) {
+    final DebuggerContextImpl context = getContext();
+    final boolean paused = context.getDebuggerSession().isPaused();
+    if (!paused || !refreshOnly) {
+      myThreadsCombo.removeAllItems();
+      synchronized (myFramesList) {
+        myFramesLastUpdateTime = getNextStamp();
+        myFramesList.getModel().clear();
+      }
+    }
+
+    if (paused) {
+      final DebugProcessImpl process = context.getDebugProcess();
+      if (process != null) {
+        process.getManagerThread().schedule(new RefreshFramePanelCommand(refreshOnly && myThreadsCombo.getItemCount() != 0));
+      }
+    }
+  }
+
+  @Override
+  public void dispose() {
+    try {
+      Disposer.dispose(myRebuildAlarm);
+    }
+    finally {
+      super.dispose();
+    }
+  }
+
+  public boolean isShowLibraryFrames() {
+    return myShowLibraryFrames;
+  }
+
+  public void setShowLibraryFrames(boolean showLibraryFrames) {
+    if (myShowLibraryFrames != showLibraryFrames) {
+      myShowLibraryFrames = showLibraryFrames;
+      rebuild(DebuggerSession.EVENT_CONTEXT);
+    }
+  }
+
+  private class RefreshFramePanelCommand extends DebuggerContextCommandImpl {
+    private final boolean myRefreshOnly;
+    private final ThreadDescriptorImpl[] myThreadDescriptorsToUpdate;
+
+    public RefreshFramePanelCommand(final boolean refreshOnly) {
+      super(getContext());
+      myRefreshOnly = refreshOnly;
+      if (refreshOnly) {
+        final int size = myThreadsCombo.getItemCount();
+        myThreadDescriptorsToUpdate = new ThreadDescriptorImpl[size];
+        for (int idx = 0; idx < size; idx++) {
+          myThreadDescriptorsToUpdate[idx] = (ThreadDescriptorImpl)myThreadsCombo.getItemAt(idx);
+        }
+      }
+      else {
+        myThreadDescriptorsToUpdate = null;
+      }
+    }
+
+    private List<ThreadDescriptorImpl> createThreadDescriptorsList() {
+      final List<ThreadReferenceProxyImpl> threads = new ArrayList<ThreadReferenceProxyImpl>(getSuspendContext().getDebugProcess().getVirtualMachineProxy().allThreads());
+      Collections.sort(threads, ThreadReferenceProxyImpl.ourComparator);
+
+      final List<ThreadDescriptorImpl> descriptors = new ArrayList<ThreadDescriptorImpl>(threads.size());
+      EvaluationContextImpl evaluationContext = getDebuggerContext().createEvaluationContext();
+
+      for (ThreadReferenceProxyImpl thread : threads) {
+        ThreadDescriptorImpl threadDescriptor = new ThreadDescriptorImpl(thread);
+        threadDescriptor.setContext(evaluationContext);
+        threadDescriptor.updateRepresentation(evaluationContext, DescriptorLabelListener.DUMMY_LISTENER);
+        descriptors.add(threadDescriptor);
+      }
+      return descriptors;
+    }
+
+    public void threadAction() {
+      if (myRefreshOnly && myThreadDescriptorsToUpdate.length != myThreadsCombo.getItemCount()) {
+        // there is no sense in refreshing combobox if thread list has changed since creation of this command
+        return;
+      }
+      
+      final DebuggerContextImpl context = getDebuggerContext();
+
+      final ThreadReferenceProxyImpl threadToSelect = context.getThreadProxy();
+      if(threadToSelect == null) {
+        return;
+      }
+
+      final SuspendContextImpl threadContext = SuspendManagerUtil.getSuspendContextForThread(context.getSuspendContext(), threadToSelect);
+      final ThreadDescriptorImpl currentThreadDescriptor = (ThreadDescriptorImpl)myThreadsCombo.getSelectedItem();
+      final ThreadReferenceProxyImpl currentThread = currentThreadDescriptor != null? currentThreadDescriptor.getThreadReference() : null;
+
+      if (myRefreshOnly && threadToSelect.equals(currentThread)) {
+        context.getDebugProcess().getManagerThread().schedule(new UpdateFramesListCommand(context, threadContext));
+      }
+      else {
+        context.getDebugProcess().getManagerThread().schedule(new RebuildFramesListCommand(context, threadContext));
+      }
+
+      if (myRefreshOnly) {
+        final EvaluationContextImpl evaluationContext = context.createEvaluationContext();
+        for (ThreadDescriptorImpl descriptor : myThreadDescriptorsToUpdate) {
+          descriptor.setContext(evaluationContext);
+          descriptor.updateRepresentation(evaluationContext, DescriptorLabelListener.DUMMY_LISTENER);
+        }
+        DebuggerInvocationUtil.swingInvokeLater(getProject(), new Runnable() {
+          public void run() {
+            try {
+              myThreadsListener.setEnabled(false);
+              selectThread(threadToSelect);
+              myFramesList.repaint();
+            }
+            finally {
+              myThreadsListener.setEnabled(true);
+            }
+          }
+        });
+      }
+      else { // full rebuild
+        refillThreadsCombo(threadToSelect);
+      }
+    }
+
+    protected void commandCancelled() {
+      if (!DebuggerManagerThreadImpl.isManagerThread()) {
+        return;
+      }
+      // context thread is not suspended
+      final DebuggerContextImpl context = getDebuggerContext();
+
+      final SuspendContextImpl suspendContext = context.getSuspendContext();
+      if (suspendContext == null) {
+        return;
+      }
+      final ThreadReferenceProxyImpl threadToSelect = context.getThreadProxy();
+      if(threadToSelect == null) {
+        return;
+      }
+
+      if (!suspendContext.isResumed()) {
+        final SuspendContextImpl threadContext = SuspendManagerUtil.getSuspendContextForThread(suspendContext, threadToSelect);
+        context.getDebugProcess().getManagerThread().schedule(new RebuildFramesListCommand(context, threadContext));
+        refillThreadsCombo(threadToSelect);
+      }
+    }
+
+    private void refillThreadsCombo(final ThreadReferenceProxyImpl threadToSelect) {
+      final List<ThreadDescriptorImpl> threadItems = createThreadDescriptorsList();
+      DebuggerInvocationUtil.swingInvokeLater(getProject(), new Runnable() {
+        public void run() {
+          try {
+            myThreadsListener.setEnabled(false);
+
+            myThreadsCombo.removeAllItems();
+            for (final ThreadDescriptorImpl threadItem : threadItems) {
+              myThreadsCombo.addItem(threadItem);
+            }
+
+            selectThread(threadToSelect);
+          }
+          finally {
+            myThreadsListener.setEnabled(true);
+          }
+        }
+      });
+    }
+
+  }
+
+  private class UpdateFramesListCommand extends SuspendContextCommandImpl {
+    private final DebuggerContextImpl myDebuggerContext;
+
+    public UpdateFramesListCommand(DebuggerContextImpl debuggerContext, SuspendContextImpl suspendContext) {
+      super(suspendContext);
+      myDebuggerContext = debuggerContext;
+    }
+
+    public void contextAction() throws Exception {
+      updateFrameList(myDebuggerContext.getThreadProxy());
+      DebuggerInvocationUtil.swingInvokeLater(getProject(), new Runnable() {
+        public void run() {
+          try {
+            myFramesListener.setEnabled(false);
+            final StackFrameProxyImpl contextFrame = getDebuggerContext().getFrameProxy();
+            if(contextFrame != null) {
+              selectFrame(contextFrame);
+            }
+          }
+          finally {
+            myFramesListener.setEnabled(true);
+          }
+        }
+      });
+
+    }
+
+    private void updateFrameList(ThreadReferenceProxyImpl thread) {
+      try {
+        if(!getSuspendContext().getDebugProcess().getSuspendManager().isSuspended(thread)) {
+          return;
+        }
+      }
+      catch (ObjectCollectedException e) {
+        return;
+      }
+      
+      final EvaluationContextImpl evaluationContext = getDebuggerContext().createEvaluationContext();
+      final List<StackFrameDescriptorImpl> descriptors = new ArrayList<StackFrameDescriptorImpl>();
+
+      synchronized (myFramesList) {
+        final DefaultListModel model = myFramesList.getModel();
+        final int size = model.getSize();
+        for (int i = 0; i < size; i++) {
+          final Object elem = model.getElementAt(i);
+          if (elem instanceof StackFrameDescriptorImpl) {
+            descriptors.add((StackFrameDescriptorImpl)elem);
+          }
+        }
+      }
+
+      for (StackFrameDescriptorImpl descriptor : descriptors) {
+        descriptor.setContext(evaluationContext);
+        descriptor.updateRepresentation(evaluationContext, DescriptorLabelListener.DUMMY_LISTENER);
+      }
+    }
+
+    public DebuggerContextImpl getDebuggerContext() {
+      return myDebuggerContext;
+    }
+  }
+
+  private class RebuildFramesListCommand extends SuspendContextCommandImpl {
+    private final DebuggerContextImpl myDebuggerContext;
+
+    public RebuildFramesListCommand(DebuggerContextImpl debuggerContext, SuspendContextImpl suspendContext) {
+      super(suspendContext);
+      myDebuggerContext = debuggerContext;
+    }
+
+    public void contextAction() throws Exception {
+      final ThreadReferenceProxyImpl thread = myDebuggerContext.getThreadProxy();
+      try {
+        if(!getSuspendContext().getDebugProcess().getSuspendManager().isSuspended(thread)) {
+          DebuggerInvocationUtil.swingInvokeLater(getProject(), new Runnable() {
+            public void run() {
+              try {
+                myFramesListener.setEnabled(false);
+                synchronized (myFramesList) {
+                  myFramesLastUpdateTime = getNextStamp();
+                  final DefaultListModel model = myFramesList.getModel();
+                  model.clear();
+                  model.addElement(new Object() {
+                    public String toString() {
+                      return DebuggerBundle.message("frame.panel.frames.not.available");
+                    }
+                  });
+                  myFramesList.setSelectedIndex(0);
+                }
+              }
+              finally {
+                myFramesListener.setEnabled(true);
+              }
+            }
+          });
+          
+          return;
+        }
+      }
+      catch (ObjectCollectedException e) {
+        return;
+      }
+
+      List<StackFrameProxyImpl> frames;
+      try {
+        frames = thread.frames();
+      }
+      catch (EvaluateException e) {
+        frames = Collections.emptyList();
+      }
+
+      final StackFrameProxyImpl contextFrame = myDebuggerContext.getFrameProxy();
+      final EvaluationContextImpl evaluationContext = myDebuggerContext.createEvaluationContext();
+      final DebuggerManagerThreadImpl managerThread = myDebuggerContext.getDebugProcess().getManagerThread();
+      final MethodsTracker tracker = new MethodsTracker();
+      final int totalFramesCount = frames.size();
+      int index = 0;
+      final IndexCounter indexCounter = new IndexCounter(totalFramesCount);
+      final long timestamp = getNextStamp();
+      for (StackFrameProxyImpl stackFrameProxy : frames) {
+        managerThread.schedule(
+          new AppendFrameCommand(
+            getSuspendContext(), 
+            stackFrameProxy, 
+            evaluationContext, 
+            tracker, 
+            index++, 
+            stackFrameProxy.equals(contextFrame),
+            timestamp, 
+            indexCounter
+          )
+        );
+      }
+    }
+  }
+
+  private void selectThread(ThreadReferenceProxyImpl toSelect) {
+    int count = myThreadsCombo.getItemCount();
+    for (int idx = 0; idx < count; idx++) {
+      ThreadDescriptorImpl item = (ThreadDescriptorImpl)myThreadsCombo.getItemAt(idx);
+      if (toSelect.equals(item.getThreadReference())) {
+        if (!item.equals(myThreadsCombo.getSelectedItem())) {
+          myThreadsCombo.setSelectedIndex(idx);
+        }
+        return;
+      }
+    }
+  }
+
+  /*invoked in swing thread*/
+  private void selectFrame(StackFrameProxy frame) {
+    synchronized (myFramesList) {
+      final int count = myFramesList.getElementCount();
+      final Object selectedValue = myFramesList.getSelectedValue();
+      final DefaultListModel model = myFramesList.getModel();
+      for (int idx = 0; idx < count; idx++) {
+        final Object elem = model.getElementAt(idx);
+        if (elem instanceof StackFrameDescriptorImpl) {
+          final StackFrameDescriptorImpl item = (StackFrameDescriptorImpl)elem;
+          if (frame.equals(item.getFrameProxy())) {
+            if (!item.equals(selectedValue)) {
+              myFramesList.setSelectedIndex(idx);
+            }
+            return;
+          }
+        }
+      }
+    }
+  }
+
+  private static class IndexCounter {
+    private final int[] myData;
+
+    private IndexCounter(int totalSize) {
+      myData = new int[totalSize];
+      for (int idx = 0; idx < totalSize; idx++) {
+        myData[idx] = 0;
+      }
+    }
+    
+    public void markCalculated(int idx){
+      myData[idx] = 1;
+    }
+    
+    public int getActualIndex(final int index) {
+      int result = 0;
+      for (int idx = 0; idx < index; idx++) {
+        result += myData[idx];
+      }
+      return result;
+    }
+  }
+  
+  private final AtomicLong myTimeCounter = new AtomicLong(0L);
+  private long getNextStamp() {
+    return myTimeCounter.incrementAndGet();
+  }
+  
+  private long myFramesLastUpdateTime = 0L;
+  
+  private class AppendFrameCommand extends SuspendContextCommandImpl {
+    private final StackFrameProxyImpl myFrame;
+    private final EvaluationContextImpl myEvaluationContext;
+    private final MethodsTracker myTracker;
+    private final int myIndexToInsert;
+    private final boolean myIsContextFrame;
+    private final long myTimestamp;
+    private final IndexCounter myCounter;
+
+    public AppendFrameCommand(SuspendContextImpl suspendContext, StackFrameProxyImpl frame, EvaluationContextImpl evaluationContext,
+                              MethodsTracker tracker, int indexToInsert, final boolean isContextFrame, final long timestamp, IndexCounter counter) {
+      super(suspendContext);
+      myFrame = frame;
+      myEvaluationContext = evaluationContext;
+      myTracker = tracker;
+      myIndexToInsert = indexToInsert;
+      myIsContextFrame = isContextFrame;
+      myTimestamp = timestamp;
+      myCounter = counter;
+    }
+
+    public void contextAction() throws Exception {
+      final StackFrameDescriptorImpl descriptor = new StackFrameDescriptorImpl(myFrame, myTracker);
+      descriptor.setContext(myEvaluationContext);
+      descriptor.updateRepresentation(myEvaluationContext, DescriptorLabelListener.DUMMY_LISTENER);
+      final Project project = getProject();
+      DebuggerInvocationUtil.swingInvokeLater(project, new Runnable() {
+        public void run() {
+          try {
+            myFramesListener.setEnabled(false);
+            synchronized (myFramesList) {
+              final DefaultListModel model = myFramesList.getModel();
+              if (myFramesLastUpdateTime < myTimestamp) {
+                myFramesLastUpdateTime = myTimestamp;
+                model.clear();
+              }
+              if (myTimestamp != myFramesLastUpdateTime) {
+                return;  // the command has expired
+              }
+              final boolean shouldHide = !myShowLibraryFrames && !myIsContextFrame && myIndexToInsert != 0 && (descriptor.isSynthetic() || descriptor.isInLibraryContent());
+              if (!shouldHide) {
+                myCounter.markCalculated(myIndexToInsert);
+                final int actualIndex = myCounter.getActualIndex(myIndexToInsert);
+                model.insertElementAt(descriptor, actualIndex);
+                if (myIsContextFrame) {
+                  myFramesList.setSelectedIndex(actualIndex);
+                }
+              }
+            }
+          }
+          finally {
+            myFramesListener.setEnabled(true);
+          }
+        }
+      });
+    }
+  }
+
+  public void requestFocus() {
+    myFramesList.requestFocus();
+  }
+
+  public OccurenceNavigator getOccurenceNavigator() {
+    return myFramesList;
+  }
+
+  public FramesList getFramesList() {
+    return myFramesList;
+  }
+
+  private class ShowLibraryFramesAction extends ToggleAction {
+    private volatile boolean myShouldShow;
+    private static final String ourTextWhenShowIsOn = "Hide Frames from Libraries";
+    private static final String ourTextWhenShowIsOff = "Show All Frames";
+
+    public ShowLibraryFramesAction() {
+      super("", "", FILTER_STACK_FRAMES_ICON);
+      myShouldShow = DebuggerSettings.getInstance().SHOW_LIBRARY_STACKFRAMES;
+    }
+
+    public void update(final AnActionEvent e) {
+      super.update(e);
+      final Presentation presentation = e.getPresentation();
+      final boolean shouldShow = !(Boolean)presentation.getClientProperty(SELECTED_PROPERTY);
+      presentation.setText(shouldShow ? ourTextWhenShowIsOn : ourTextWhenShowIsOff);
+    }
+
+    public boolean isSelected(AnActionEvent e) {
+      return !myShouldShow;
+    }
+
+    public void setSelected(AnActionEvent e, boolean enabled) {
+      myShouldShow = !enabled;
+      DebuggerSettings.getInstance().SHOW_LIBRARY_STACKFRAMES = myShouldShow;
+      setShowLibraryFrames(myShouldShow);
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/GenericDebuggerParametersPatcherConfigurable.form b/java/debugger/impl/src/com/intellij/debugger/ui/GenericDebuggerParametersPatcherConfigurable.form
new file mode 100644
index 0000000..01cb795
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/GenericDebuggerParametersPatcherConfigurable.form
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.debugger.impl.GenericDebuggerParametersRunnerConfigurable">
+  <grid id="a1cd4" binding="myPanel" layout-manager="GridLayoutManager" row-count="3" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+    <margin top="0" left="0" bottom="0" right="0"/>
+    <constraints>
+      <xy x="53" y="171" width="441" height="92"/>
+    </constraints>
+    <properties/>
+    <border type="none"/>
+    <children>
+      <grid id="86bed" binding="myShMemPanel" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+        <margin top="0" left="0" bottom="0" right="0"/>
+        <constraints>
+          <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties/>
+        <border type="none"/>
+        <children>
+          <component id="9f41f" class="javax.swing.JLabel">
+            <constraints>
+              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="4" fill="0" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <text resource-bundle="messages/DebuggerBundle" key="label.generic.debugger.parameters.patcher.configurable.shmem.address"/>
+            </properties>
+          </component>
+          <component id="af504" class="javax.swing.JTextField" binding="myAddressField">
+            <constraints>
+              <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="1" indent="0" use-parent-layout="false">
+                <preferred-size width="150" height="-1"/>
+              </grid>
+            </constraints>
+            <properties>
+              <text value=""/>
+            </properties>
+          </component>
+        </children>
+      </grid>
+      <grid id="c2b5" binding="myPortPanel" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+        <margin top="0" left="0" bottom="0" right="0"/>
+        <constraints>
+          <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties/>
+        <border type="none"/>
+        <children>
+          <component id="6e48a" class="javax.swing.JLabel">
+            <constraints>
+              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="4" fill="0" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <text resource-bundle="messages/DebuggerBundle" key="label.generic.debugger.parameters.patcher.configurable.port"/>
+            </properties>
+          </component>
+          <component id="5ffe7" class="javax.swing.JTextField" binding="myPortField">
+            <constraints>
+              <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="1" indent="0" use-parent-layout="false">
+                <preferred-size width="150" height="-1"/>
+              </grid>
+            </constraints>
+            <properties>
+              <text value=""/>
+            </properties>
+          </component>
+        </children>
+      </grid>
+      <component id="aad8d" class="javax.swing.JButton" binding="myDebuggerSettings">
+        <constraints>
+          <grid row="1" column="1" row-span="2" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties>
+          <text resource-bundle="messages/DebuggerBundle" key="button.debugger.settings"/>
+        </properties>
+      </component>
+      <grid id="b10c7" binding="myTransportPanel" layout-manager="GridLayoutManager" row-count="1" column-count="4" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+        <margin top="0" left="0" bottom="0" right="0"/>
+        <constraints>
+          <grid row="0" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties/>
+        <border type="none"/>
+        <children>
+          <component id="63d09" class="javax.swing.JLabel">
+            <constraints>
+              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <text resource-bundle="messages/DebuggerBundle" key="label.generic.debugger.parameters.patcher.configurable.transport"/>
+            </properties>
+          </component>
+          <component id="f3bb4" class="javax.swing.JRadioButton" binding="mySocketTransport">
+            <constraints>
+              <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <selected value="true"/>
+              <text resource-bundle="messages/DebuggerBundle" key="label.generic.debugger.parameters.patcher.configurable.socket"/>
+            </properties>
+          </component>
+          <component id="3bb61" class="javax.swing.JRadioButton" binding="myShmemTransport">
+            <constraints>
+              <grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <text resource-bundle="messages/DebuggerBundle" key="label.generic.debugger.parameters.patcher.configurable.shmem"/>
+            </properties>
+          </component>
+          <hspacer id="b3e0f">
+            <constraints>
+              <grid row="0" column="3" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+            </constraints>
+          </hspacer>
+        </children>
+      </grid>
+    </children>
+  </grid>
+</form>
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/GetJPDADialog.java b/java/debugger/impl/src/com/intellij/debugger/ui/GetJPDADialog.java
new file mode 100644
index 0000000..c88c008
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/GetJPDADialog.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2000-2012 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.
+ */
+
+/*
+ * @author: Eugene Zhuravlev
+ * Date: Oct 16, 2002
+ * Time: 5:31:46 PM
+ */
+package com.intellij.debugger.ui;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.ide.BrowserUtil;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.ui.DoubleClickListener;
+import com.intellij.ui.JBColor;
+import org.jetbrains.annotations.NonNls;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.MouseEvent;
+
+public class GetJPDADialog extends DialogWrapper {
+  private static final @NonNls String JPDA_URL = "http://java.sun.com/products/jpda";
+
+  public GetJPDADialog() {
+    super(false);
+    setTitle(DebuggerBundle.message("get.jpda.dialog.title"));
+    setResizable(false);
+    init();
+  }
+
+  protected Action[] createActions() {
+    return new Action[]{getOKAction()};
+  }
+
+  protected JComponent createCenterPanel() {
+    final JPanel _panel1 = new JPanel(new BorderLayout());
+
+    JPanel _panel2 = new JPanel(new BorderLayout());
+    _panel2.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+    //"Debug libraries are missig from JDK home.\nIn order for debugger to start, the libraries should be installed.\nPlease visit http://java.sun.com/products/jpda"
+    JLabel label1 = new JLabel(DebuggerBundle.message("label.get.jpda.dialog.prompt"));
+    //label1.setForeground(Color.black);
+    JLabel label2 = new JLabel(JPDA_URL);
+    new DoubleClickListener() {
+      @Override
+      protected boolean onDoubleClick(MouseEvent e) {
+        BrowserUtil.launchBrowser(JPDA_URL);
+        return true;
+      }
+    }.installOn(label2);
+    label2.setForeground(JBColor.BLUE.darker());
+    label2.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+    _panel2.add(new JLabel(DebuggerBundle.message("label.get.jpda.dialog.error.description")), BorderLayout.NORTH);
+    _panel2.add(label1, BorderLayout.WEST);
+    _panel2.add(label2, BorderLayout.EAST);
+    _panel1.add(_panel2, BorderLayout.NORTH);
+
+    JPanel content = new JPanel(new GridLayout(2, 1, 10, 10));
+
+    _panel1.add(content, BorderLayout.CENTER);
+    return _panel1;
+  }
+}
+
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapProgressImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapProgressImpl.java
new file mode 100644
index 0000000..b2b0091
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapProgressImpl.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerInvocationUtil;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.debugger.impl.HotSwapProgress;
+import com.intellij.debugger.settings.DebuggerSettings;
+import com.intellij.notification.NotificationGroup;
+import com.intellij.notification.NotificationType;
+import com.intellij.openapi.progress.PerformInBackgroundOption;
+import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator;
+import com.intellij.openapi.progress.util.ProgressWindow;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.wm.ToolWindowId;
+import com.intellij.util.StringBuilderSpinAllocator;
+import com.intellij.util.ui.MessageCategory;
+import gnu.trove.TIntObjectHashMap;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class HotSwapProgressImpl extends HotSwapProgress{
+  static final NotificationGroup NOTIFICATION_GROUP = NotificationGroup.toolWindowGroup("HotSwap", ToolWindowId.DEBUG, true);
+
+  TIntObjectHashMap<List<String>> myMessages = new TIntObjectHashMap<List<String>>();
+  private final ProgressWindow myProgressWindow;
+  private String myTitle = DebuggerBundle.message("progress.hot.swap.title");
+
+  public HotSwapProgressImpl(Project project) {
+    super(project);
+    myProgressWindow = new BackgroundableProcessIndicator(getProject(), myTitle, new PerformInBackgroundOption() {
+      public boolean shouldStartInBackground() {
+        return DebuggerSettings.getInstance().HOTSWAP_IN_BACKGROUND;
+      }
+
+      public void processSentToBackground() {
+      }
+
+    }, null, null, true) {
+      public void cancel() {
+        HotSwapProgressImpl.this.cancel();
+        super.cancel();
+      }
+    };
+  }
+
+  public void finished() {
+    super.finished();
+
+    final List<String> errors = getMessages(MessageCategory.ERROR);
+    final List<String> warnings = getMessages(MessageCategory.WARNING);
+    if (!errors.isEmpty()) {
+      NOTIFICATION_GROUP.createNotification(DebuggerBundle.message("status.hot.swap.completed.with.errors"), buildMessage(errors),
+                                                              NotificationType.ERROR, null).notify(getProject());
+    }
+    else if (!warnings.isEmpty()){
+      NOTIFICATION_GROUP.createNotification(DebuggerBundle.message("status.hot.swap.completed.with.warnings"),
+                                            buildMessage(warnings), NotificationType.WARNING, null).notify(getProject());
+    }
+    else if (!myMessages.isEmpty()){
+      List<String> messages = new ArrayList<String>();
+      for (int category : myMessages.keys()) {
+        messages.addAll(getMessages(category));
+      }
+      NOTIFICATION_GROUP.createNotification(buildMessage(messages), NotificationType.INFORMATION).notify(getProject());
+    }
+  }
+
+  private List<String> getMessages(int category) {
+    final List<String> messages = myMessages.get(category);
+    return messages == null? Collections.<String>emptyList() : messages;
+  }
+    
+  private static String buildMessage(List<String> messages) {
+    return StringUtil.trimEnd(StringUtil.join(messages, " \n").trim(), ";");
+  }
+  
+  public void addMessage(DebuggerSession session, final int type, final String text) {
+    List<String> messages = myMessages.get(type);
+    if (messages == null) {
+      messages = new ArrayList<String>();
+      myMessages.put(type, messages);
+    }
+    final StringBuilder builder = StringBuilderSpinAllocator.alloc();
+    try {
+      builder.append(session.getSessionName()).append(": ").append(text).append(";");
+      messages.add(builder.toString());
+    }
+    finally {
+      StringBuilderSpinAllocator.dispose(builder);
+    }
+  }
+
+  public void setText(final String text) {
+    DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
+      public void run() {
+        if (!myProgressWindow.isCanceled() && myProgressWindow.isRunning()) {
+          myProgressWindow.setText(text);
+        }
+      }
+    }, myProgressWindow.getModalityState());
+
+  }
+
+  public void setTitle(final String text) {
+    DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
+      public void run() {
+        if (!myProgressWindow.isCanceled() && myProgressWindow.isRunning()) {
+        myProgressWindow.setTitle(text);
+        }
+      }
+    }, myProgressWindow.getModalityState());
+
+  }
+
+  public void setFraction(final double v) {
+    DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
+      public void run() {
+        if (!myProgressWindow.isCanceled() && myProgressWindow.isRunning()) {
+        myProgressWindow.setFraction(v);
+        }
+      }
+    }, myProgressWindow.getModalityState());
+  }
+
+  public boolean isCancelled() {
+    return myProgressWindow.isCanceled();
+  }
+
+  public ProgressIndicator getProgressIndicator() {
+     return myProgressWindow;
+  }
+
+  public void setDebuggerSession(DebuggerSession session) {
+    myTitle = DebuggerBundle.message("progress.hot.swap.title") + " : " + session.getSessionName();
+    myProgressWindow.setTitle(myTitle);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapUI.java b/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapUI.java
new file mode 100644
index 0000000..5cae3a8
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapUI.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.debugger.impl.DebuggerSession;
+
+/**
+ * @author nik
+ */
+public abstract class HotSwapUI {
+  public static HotSwapUI getInstance(Project project) {
+    return project.getComponent(HotSwapUI.class);
+  }
+
+  public abstract void reloadChangedClasses(DebuggerSession session, boolean compileBeforeHotswap);
+
+  public abstract void dontPerformHotswapAfterThisCompilation();
+
+
+  public abstract void addListener(HotSwapVetoableListener listener);
+
+  public abstract void removeListener(HotSwapVetoableListener listener);
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapUIImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapUIImpl.java
new file mode 100644
index 0000000..7683bc1
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapUIImpl.java
@@ -0,0 +1,347 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui;
+
+import com.intellij.CommonBundle;
+import com.intellij.compiler.CompilerWorkspaceConfiguration;
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerManager;
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.impl.DebuggerManagerAdapter;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.debugger.impl.HotSwapFile;
+import com.intellij.debugger.impl.HotSwapManager;
+import com.intellij.debugger.settings.DebuggerSettings;
+import com.intellij.notification.NotificationType;
+import com.intellij.openapi.application.Application;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.ModalityState;
+import com.intellij.openapi.compiler.CompilationStatusListener;
+import com.intellij.openapi.compiler.CompileContext;
+import com.intellij.openapi.compiler.CompilerManager;
+import com.intellij.openapi.compiler.CompilerTopics;
+import com.intellij.openapi.components.ProjectComponent;
+import com.intellij.openapi.progress.ProgressManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.openapi.ui.Messages;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.util.Ref;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.util.PairFunction;
+import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.messages.MessageBus;
+import com.intellij.util.messages.MessageBusConnection;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * User: lex
+ * Date: Oct 2, 2003
+ * Time: 6:00:55 PM
+ */
+public class HotSwapUIImpl extends HotSwapUI implements ProjectComponent {
+  private final List<HotSwapVetoableListener> myListeners = ContainerUtil.createEmptyCOWList();
+  private boolean myAskBeforeHotswap = true;
+  private final Project myProject;
+  private boolean myPerformHotswapAfterThisCompilation = true;
+
+  public HotSwapUIImpl(final Project project, final MessageBus bus, DebuggerManager debugManager) {
+    myProject = project;
+
+    ((DebuggerManagerEx)debugManager).addDebuggerManagerListener(new DebuggerManagerAdapter() {
+      private MessageBusConnection myConn = null;
+      private int mySessionCount = 0;
+
+      @Override
+      public void sessionAttached(DebuggerSession session) {
+        if (mySessionCount++ == 0) {
+          myConn = bus.connect();
+          myConn.subscribe(CompilerTopics.COMPILATION_STATUS, new MyCompilationStatusListener());
+        }
+      }
+
+      @Override
+      public void sessionDetached(DebuggerSession session) {
+        mySessionCount = Math.max(0, mySessionCount - 1);
+        if (mySessionCount == 0) {
+          final MessageBusConnection conn = myConn;
+          if (conn != null) {
+            Disposer.dispose(conn);
+            myConn = null;
+          }
+        }
+      }
+    });
+  }
+
+  public void projectOpened() {
+  }
+
+  public void projectClosed() {
+  }
+
+  @NotNull
+  public String getComponentName() {
+    return "HotSwapUI";
+  }
+
+  public void initComponent() {
+  }
+
+  public void disposeComponent() {
+
+  }
+
+  public void addListener(HotSwapVetoableListener listener) {
+    myListeners.add(listener);
+  }
+
+  public void removeListener(HotSwapVetoableListener listener) {
+    myListeners.remove(listener);
+  }
+
+  private boolean shouldDisplayHangWarning(DebuggerSettings settings, List<DebuggerSession> sessions) {
+    if (!settings.HOTSWAP_HANG_WARNING_ENABLED) {
+      return false;
+    }
+    // todo: return false if yourkit agent is inactive
+    for (DebuggerSession session : sessions) {
+      if (session.isPaused()) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  private void hotSwapSessions(final List<DebuggerSession> sessions, @Nullable final Map<String, List<String>> generatedPaths) {
+    final boolean shouldAskBeforeHotswap = myAskBeforeHotswap;
+    myAskBeforeHotswap = true;
+
+    // need this because search with PSI is perormed during hotswap
+    PsiDocumentManager.getInstance(myProject).commitAllDocuments();
+
+    final DebuggerSettings settings = DebuggerSettings.getInstance();
+    final String runHotswap = settings.RUN_HOTSWAP_AFTER_COMPILE;
+    final boolean shouldDisplayHangWarning = shouldDisplayHangWarning(settings, sessions);
+
+    if (shouldAskBeforeHotswap && DebuggerSettings.RUN_HOTSWAP_NEVER.equals(runHotswap)) {
+      return;
+    }
+
+    final boolean isOutOfProcessMode = CompilerWorkspaceConfiguration.getInstance(myProject).useOutOfProcessBuild();
+    final boolean shouldPerformScan = !isOutOfProcessMode || generatedPaths == null;
+
+    final HotSwapProgressImpl findClassesProgress;
+    if (shouldPerformScan) {
+      findClassesProgress = new HotSwapProgressImpl(myProject);
+    }
+    else {
+      boolean createProgress = false;
+      for (DebuggerSession session : sessions) {
+        if (session.isModifiedClassesScanRequired()) {
+          createProgress = true;
+          break;
+        }
+      }
+      findClassesProgress = createProgress ? new HotSwapProgressImpl(myProject) : null;
+    }
+
+    ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
+      public void run() {
+        final Map<DebuggerSession, Map<String, HotSwapFile>> modifiedClasses;
+        if (shouldPerformScan) {
+          modifiedClasses = scanForModifiedClassesWithProgress(sessions, findClassesProgress, !isOutOfProcessMode);
+        }
+        else {
+          final List<DebuggerSession> toScan = new ArrayList<DebuggerSession>();
+          final List<DebuggerSession> toUseGenerated = new ArrayList<DebuggerSession>();
+          for (DebuggerSession session : sessions) {
+            (session.isModifiedClassesScanRequired() ? toScan : toUseGenerated).add(session);
+            session.setModifiedClassesScanRequired(false);
+          }
+          modifiedClasses = new HashMap<DebuggerSession, Map<String, HotSwapFile>>();
+          if (!toUseGenerated.isEmpty()) {
+            modifiedClasses.putAll(HotSwapManager.findModifiedClasses(toUseGenerated, generatedPaths));
+          }
+          if (!toScan.isEmpty()) {
+            modifiedClasses.putAll(scanForModifiedClassesWithProgress(toScan, findClassesProgress, !isOutOfProcessMode));
+          }
+        }
+
+        final Application application = ApplicationManager.getApplication();
+        if (modifiedClasses.isEmpty()) {
+          final String message = DebuggerBundle.message("status.hotswap.uptodate");
+          HotSwapProgressImpl.NOTIFICATION_GROUP.createNotification(message, NotificationType.INFORMATION).notify(myProject);
+          return;
+        }
+
+        application.invokeLater(new Runnable() {
+          public void run() {
+            if (shouldAskBeforeHotswap && !DebuggerSettings.RUN_HOTSWAP_ALWAYS.equals(runHotswap)) {
+              final RunHotswapDialog dialog = new RunHotswapDialog(myProject, sessions, shouldDisplayHangWarning);
+              dialog.show();
+              if (!dialog.isOK()) {
+                for (DebuggerSession session : modifiedClasses.keySet()) {
+                  session.setModifiedClassesScanRequired(true);
+                }
+                return;
+              }
+              final Set<DebuggerSession> toReload = new HashSet<DebuggerSession>(dialog.getSessionsToReload());
+              for (DebuggerSession session : modifiedClasses.keySet()) {
+                if (!toReload.contains(session)) {
+                  session.setModifiedClassesScanRequired(true);
+                }
+              }
+              modifiedClasses.keySet().retainAll(toReload);
+            }
+            else {
+              if (shouldDisplayHangWarning) {
+                final int answer = Messages.showCheckboxMessageDialog(
+                  DebuggerBundle.message("hotswap.dialog.hang.warning"),
+                  DebuggerBundle.message("hotswap.dialog.title"),
+                  new String[]{"Perform &Reload Classes", "&Skip Reload Classes"},
+                  CommonBundle.message("dialog.options.do.not.show"),
+                  false, 1, 1, Messages.getWarningIcon(),
+                  new PairFunction<Integer, JCheckBox, Integer>() {
+                    @Override
+                    public Integer fun(Integer exitCode, JCheckBox cb) {
+                      settings.HOTSWAP_HANG_WARNING_ENABLED = !cb.isSelected();
+                      return exitCode == DialogWrapper.OK_EXIT_CODE ? exitCode : DialogWrapper.CANCEL_EXIT_CODE;
+                    }
+                  }
+                );
+                if (answer == DialogWrapper.CANCEL_EXIT_CODE) {
+                  for (DebuggerSession session : modifiedClasses.keySet()) {
+                    session.setModifiedClassesScanRequired(true);
+                  }
+                  return;
+                }
+              }
+            }
+
+            if (!modifiedClasses.isEmpty()) {
+              final HotSwapProgressImpl progress = new HotSwapProgressImpl(myProject);
+              application.executeOnPooledThread(new Runnable() {
+                public void run() {
+                  reloadModifiedClasses(modifiedClasses, progress);
+                }
+              });
+            }
+          }
+        }, ModalityState.NON_MODAL);
+      }
+    });
+  }
+
+  private static Map<DebuggerSession, Map<String, HotSwapFile>> scanForModifiedClassesWithProgress(final List<DebuggerSession> sessions,
+                                                                                                   final HotSwapProgressImpl progress,
+                                                                                                   final boolean scanWithVFS) {
+    final Ref<Map<DebuggerSession, Map<String, HotSwapFile>>> result = Ref.create(null);
+    ProgressManager.getInstance().runProcess(new Runnable() {
+      public void run() {
+        try {
+          result.set(HotSwapManager.scanForModifiedClasses(sessions, progress, scanWithVFS));
+        }
+        finally {
+          progress.finished();
+        }
+      }
+    }, progress.getProgressIndicator());
+    return result.get();
+  }
+
+  private static void reloadModifiedClasses(final Map<DebuggerSession, Map<String, HotSwapFile>> modifiedClasses,
+                                            final HotSwapProgressImpl progress) {
+    ProgressManager.getInstance().runProcess(new Runnable() {
+      public void run() {
+        HotSwapManager.reloadModifiedClasses(modifiedClasses, progress);
+        progress.finished();
+      }
+    }, progress.getProgressIndicator());
+  }
+
+  public void reloadChangedClasses(final DebuggerSession session, boolean compileBeforeHotswap) {
+    dontAskHotswapAfterThisCompilation();
+    if (compileBeforeHotswap) {
+      CompilerManager.getInstance(session.getProject()).make(null);
+    }
+    else {
+      if (session.isAttached()) {
+        hotSwapSessions(Collections.singletonList(session), null);
+      }
+    }
+  }
+
+  public void dontPerformHotswapAfterThisCompilation() {
+    myPerformHotswapAfterThisCompilation = false;
+  }
+
+  public void dontAskHotswapAfterThisCompilation() {
+    myAskBeforeHotswap = false;
+  }
+
+  private class MyCompilationStatusListener implements CompilationStatusListener {
+
+    private final AtomicReference<Map<String, List<String>>>
+      myGeneratedPaths = new AtomicReference<Map<String, List<String>>>(new HashMap<String, List<String>>());
+
+    public void fileGenerated(String outputRoot, String relativePath) {
+      if (StringUtil.endsWith(relativePath, ".class")) {
+        // collect only classes
+        final Map<String, List<String>> map = myGeneratedPaths.get();
+        List<String> paths = map.get(outputRoot);
+        if (paths == null) {
+          paths = new ArrayList<String>();
+          map.put(outputRoot, paths);
+        }
+        paths.add(relativePath);
+      }
+    }
+
+    public void compilationFinished(boolean aborted, int errors, int warnings, CompileContext compileContext) {
+      final Map<String, List<String>> generated = myGeneratedPaths.getAndSet(new HashMap<String, List<String>>());
+      if (myProject.isDisposed()) {
+        return;
+      }
+
+      if (errors == 0 && !aborted && myPerformHotswapAfterThisCompilation) {
+        for (HotSwapVetoableListener listener : myListeners) {
+          if (!listener.shouldHotSwap(compileContext)) {
+            return;
+          }
+        }
+
+        final List<DebuggerSession> sessions = new ArrayList<DebuggerSession>();
+        Collection<DebuggerSession> debuggerSessions = DebuggerManagerEx.getInstanceEx(myProject).getSessions();
+        for (final DebuggerSession debuggerSession : debuggerSessions) {
+          if (debuggerSession.isAttached() && debuggerSession.getProcess().canRedefineClasses()) {
+            sessions.add(debuggerSession);
+          }
+        }
+        if (!sessions.isEmpty()) {
+          hotSwapSessions(sessions, generated);
+        }
+      }
+      myPerformHotswapAfterThisCompilation = true;
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapVetoableListener.java b/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapVetoableListener.java
new file mode 100644
index 0000000..105f5d4
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapVetoableListener.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui;
+
+import com.intellij.openapi.compiler.CompileContext;
+
+/**
+ * @author nik
+ */
+public interface HotSwapVetoableListener {
+
+  boolean shouldHotSwap(CompileContext finishedCompilationContext);
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/InstanceFilterEditor.java b/java/debugger/impl/src/com/intellij/debugger/ui/InstanceFilterEditor.java
new file mode 100644
index 0000000..7970a9c
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/InstanceFilterEditor.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.Messages;
+import com.intellij.ui.classFilter.ClassFilter;
+import com.intellij.ui.classFilter.ClassFilterEditor;
+import com.intellij.util.IconUtil;
+
+import javax.swing.*;
+
+/**
+ * User: lex
+ * Date: Aug 29, 2003
+ * Time: 2:38:30 PM
+ */
+public class InstanceFilterEditor extends ClassFilterEditor {
+  public InstanceFilterEditor(Project project) {
+    super(project);
+  }
+
+  protected void addClassFilter() {
+    String idString = Messages.showInputDialog(myProject, DebuggerBundle.message("add.instance.filter.dialog.prompt"), DebuggerBundle.message("add.instance.filter.dialog.title"), Messages.getQuestionIcon());
+    if (idString != null) {
+      ClassFilter filter = createFilter(idString);
+      if(filter != null){
+        myTableModel.addRow(filter);
+        int row = myTableModel.getRowCount() - 1;
+        myTable.getSelectionModel().setSelectionInterval(row, row);
+        myTable.scrollRectToVisible(myTable.getCellRect(row, 0, true));
+
+      }
+      myTable.requestFocus();
+    }
+  }
+
+  protected String getAddButtonText() {
+    return DebuggerBundle.message("button.add");
+  }
+
+  @Override
+  protected Icon getAddButtonIcon() {
+    return IconUtil.getAddIcon();
+  }
+
+  @Override
+  protected boolean addPatternButtonVisible() {
+    return false;
+  }
+
+  protected ClassFilter createFilter(String pattern) {
+    try {
+      Long.parseLong(pattern);
+      return super.createFilter(pattern);
+    } catch (NumberFormatException e) {
+      Messages.showMessageDialog(this, DebuggerBundle.message("add.instance.filter.dialog.error.numeric.value.expected"), DebuggerBundle.message("add.instance.filter.dialog.title"), Messages.getErrorIcon());
+      return null;
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/JavaDebuggerSupport.java b/java/debugger/impl/src/com/intellij/debugger/ui/JavaDebuggerSupport.java
new file mode 100644
index 0000000..9ae2a3d
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/JavaDebuggerSupport.java
@@ -0,0 +1,332 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui;
+
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.actions.*;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.settings.*;
+import com.intellij.debugger.ui.breakpoints.*;
+import com.intellij.ide.DataManager;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.PlatformDataKeys;
+import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.markup.GutterIconRenderer;
+import com.intellij.openapi.editor.markup.RangeHighlighter;
+import com.intellij.openapi.options.Configurable;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.project.ProjectManager;
+import com.intellij.openapi.util.Key;
+import com.intellij.util.containers.ContainerUtil;
+import com.intellij.xdebugger.AbstractDebuggerSession;
+import com.intellij.xdebugger.impl.breakpoints.ui.BreakpointItem;
+import com.intellij.xdebugger.breakpoints.ui.XBreakpointGroupingRule;
+import com.intellij.xdebugger.impl.DebuggerSupport;
+import com.intellij.xdebugger.impl.actions.DebuggerActionHandler;
+import com.intellij.xdebugger.impl.actions.DebuggerToggleActionHandler;
+import com.intellij.xdebugger.impl.actions.EditBreakpointActionHandler;
+import com.intellij.xdebugger.impl.actions.MarkObjectActionHandler;
+import com.intellij.xdebugger.impl.breakpoints.ui.BreakpointPanelProvider;
+import com.intellij.xdebugger.impl.evaluate.quick.common.QuickEvaluateHandler;
+import com.intellij.xdebugger.impl.settings.DebuggerSettingsPanelProvider;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * @author nik
+ */
+public class JavaDebuggerSupport extends DebuggerSupport {
+  private final JavaBreakpointPanelProvider myBreakpointPanelProvider = new JavaBreakpointPanelProvider();
+  private final StepOverActionHandler myStepOverActionHandler = new StepOverActionHandler();
+  private final StepIntoActionHandler myStepIntoActionHandler = new StepIntoActionHandler();
+  private final StepOutActionHandler myStepOutActionHandler = new StepOutActionHandler();
+  private final ForceStepOverActionHandler myForceStepOverActionHandler = new ForceStepOverActionHandler();
+  private final ForceStepIntoActionHandler myForceStepIntoActionHandler = new ForceStepIntoActionHandler();
+  private final RunToCursorActionHandler myRunToCursorActionHandler = new RunToCursorActionHandler();
+  private final ForceRunToCursorActionHandler myForceRunToCursorActionHandler = new ForceRunToCursorActionHandler();
+  private final ResumeActionHandler myResumeActionHandler = new ResumeActionHandler();
+  private final PauseActionHandler myPauseActionHandler = new PauseActionHandler();
+  private final ToggleLineBreakpointActionHandler myToggleLineBreakpointActionHandler = new ToggleLineBreakpointActionHandler();
+  private final ShowExecutionPointActionHandler myShowExecutionPointActionHandler = new ShowExecutionPointActionHandler();
+  private final EvaluateActionHandler myEvaluateActionHandler = new EvaluateActionHandler();
+  private final QuickEvaluateActionHandler myQuickEvaluateHandler = new QuickEvaluateActionHandler();
+  private final JavaDebuggerSettingsPanelProvider myDebuggerSettingsPanelProvider = new JavaDebuggerSettingsPanelProvider();
+  private final MuteBreakpointsActionHandler myMuteBreakpointsHandler = new MuteBreakpointsActionHandler();
+  private final DebuggerActionHandler mySmartStepIntoHandler = new JvmSmartStepIntoActionHandler();
+  private final DebuggerActionHandler myAddToWatchedActionHandler = new AddToWatchActionHandler();
+  private final JavaMarkObjectActionHandler myMarkObjectActionHandler = new JavaMarkObjectActionHandler();
+  private final JavaEditBreakpointActionHandler myEditBreakpointActionHandler = new JavaEditBreakpointActionHandler();
+
+  @NotNull
+  public BreakpointPanelProvider<?> getBreakpointPanelProvider() {
+    return myBreakpointPanelProvider;
+  }
+
+  @NotNull
+  public DebuggerActionHandler getStepOverHandler() {
+    return myStepOverActionHandler;
+  }
+
+  @NotNull
+  public DebuggerActionHandler getStepIntoHandler() {
+    return myStepIntoActionHandler;
+  }
+
+  @NotNull
+  public DebuggerActionHandler getSmartStepIntoHandler() {
+    return mySmartStepIntoHandler;
+  }
+
+  @NotNull
+  public DebuggerActionHandler getStepOutHandler() {
+    return myStepOutActionHandler;
+  }
+
+  @NotNull
+  public DebuggerActionHandler getForceStepOverHandler() {
+    return myForceStepOverActionHandler;
+  }
+
+  @NotNull
+  public DebuggerActionHandler getForceStepIntoHandler() {
+    return myForceStepIntoActionHandler;
+  }
+
+  @NotNull
+  public DebuggerActionHandler getRunToCursorHandler() {
+    return myRunToCursorActionHandler;
+  }
+
+  @NotNull
+  public DebuggerActionHandler getForceRunToCursorHandler() {
+    return myForceRunToCursorActionHandler;
+  }
+
+  @NotNull
+  public DebuggerActionHandler getResumeActionHandler() {
+    return myResumeActionHandler;
+  }
+
+  @NotNull
+  public DebuggerActionHandler getPauseHandler() {
+    return myPauseActionHandler;
+  }
+
+  @NotNull
+  public DebuggerActionHandler getToggleLineBreakpointHandler() {
+    return myToggleLineBreakpointActionHandler;
+  }
+
+  @NotNull
+  public DebuggerActionHandler getShowExecutionPointHandler() {
+    return myShowExecutionPointActionHandler;
+  }
+
+  @NotNull
+  public DebuggerActionHandler getEvaluateHandler() {
+    return myEvaluateActionHandler;
+  }
+
+  @NotNull
+  public QuickEvaluateHandler getQuickEvaluateHandler() {
+    return myQuickEvaluateHandler;
+  }
+
+  @NotNull
+  @Override
+  public DebuggerActionHandler getAddToWatchesActionHandler() {
+    return myAddToWatchedActionHandler;
+  }
+
+  @NotNull
+  public DebuggerToggleActionHandler getMuteBreakpointsHandler() {
+    return myMuteBreakpointsHandler;
+  }
+
+  @NotNull
+  @Override
+  public MarkObjectActionHandler getMarkObjectHandler() {
+    return myMarkObjectActionHandler;
+  }
+
+  @Override
+  public AbstractDebuggerSession getCurrentSession(@NotNull Project project) {
+    final DebuggerContextImpl context = (DebuggerManagerEx.getInstanceEx(project)).getContext();
+    return context != null ? context.getDebuggerSession() : null;
+  }
+
+  @NotNull
+  @Override
+  public EditBreakpointActionHandler getEditBreakpointAction() {
+    return myEditBreakpointActionHandler;
+  }
+
+  @NotNull
+  public DebuggerSettingsPanelProvider getSettingsPanelProvider() {
+    return myDebuggerSettingsPanelProvider;
+  }
+
+  private static class JavaBreakpointPanelProvider extends BreakpointPanelProvider<Breakpoint> {
+    private List<MyBreakpointManagerListener> myListeners = ContainerUtil.createEmptyCOWList();
+
+    @Override
+    public AnAction[] getAddBreakpointActions(@NotNull Project project) {
+      List<AnAction> result = new ArrayList<AnAction>();
+      BreakpointFactory[] breakpointFactories = BreakpointFactory.getBreakpointFactories();
+      for (BreakpointFactory breakpointFactory : breakpointFactories) {
+        result.add(new AddJavaBreakpointAction(breakpointFactory));
+      }
+      return result.toArray(new AnAction[result.size()]);
+    }
+
+    @Override
+    public void createBreakpointsGroupingRules(Collection<XBreakpointGroupingRule> rules) {
+      rules.add(new XBreakpointGroupingByCategoryRule());
+      rules.add(new XBreakpointGroupingByPackageRule());
+      rules.add(new XBreakpointGroupingByClassRule());
+    }
+
+    @Override
+    public void addListener(final BreakpointsListener listener, Project project) {
+      BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(getCurrentProject()).getBreakpointManager();
+      final MyBreakpointManagerListener listener1 = new MyBreakpointManagerListener(listener, breakpointManager);
+      breakpointManager.addBreakpointManagerListener(listener1);
+      myListeners.add(listener1);
+    }
+
+    @Override
+    public void removeListener(BreakpointsListener listener) {
+      for (MyBreakpointManagerListener managerListener : myListeners) {
+        if (managerListener.myListener == listener) {
+          BreakpointManager manager = managerListener.myBreakpointManager;
+          manager.removeBreakpointManagerListener(managerListener);
+          myListeners.remove(managerListener);
+          break;
+        }
+      }
+    }
+
+    public int getPriority() {
+      return 1;
+    }
+
+    public Breakpoint findBreakpoint(@NotNull final Project project, @NotNull final Document document, final int offset) {
+      return DebuggerManagerEx.getInstanceEx(project).getBreakpointManager().findBreakpoint(document, offset, null);
+    }
+
+    @Override
+    public GutterIconRenderer getBreakpointGutterIconRenderer(Object breakpoint) {
+      if (breakpoint instanceof BreakpointWithHighlighter) {
+        final RangeHighlighter highlighter = ((BreakpointWithHighlighter)breakpoint).getHighlighter();
+        if (highlighter != null) {
+          return highlighter.getGutterIconRenderer();
+        }
+      }
+      return null;
+    }
+
+    public void onDialogClosed(final Project project) {
+      DebuggerManagerEx.getInstanceEx(project).getBreakpointManager().updateAllRequests();
+    }
+
+    @Override
+    public void provideBreakpointItems(Project project, Collection<BreakpointItem> items) {
+      for (BreakpointFactory breakpointFactory : BreakpointFactory.getBreakpointFactories()) {
+        Key<? extends Breakpoint> category = breakpointFactory.getBreakpointCategory();
+        Breakpoint[] breakpoints = DebuggerManagerEx.getInstanceEx(project).getBreakpointManager().getBreakpoints(category);
+        for (Breakpoint breakpoint : breakpoints) {
+          items.add(breakpointFactory.createBreakpointItem(breakpoint));
+        }
+      }
+    }
+
+    private static class AddJavaBreakpointAction extends AnAction {
+      private BreakpointFactory myBreakpointFactory;
+
+      public AddJavaBreakpointAction(BreakpointFactory breakpointFactory) {
+        myBreakpointFactory = breakpointFactory;
+        Presentation p = getTemplatePresentation();
+        p.setIcon(myBreakpointFactory.getIcon());
+        p.setText(breakpointFactory.getDisplayName());
+      }
+
+      @Override
+      public void update(AnActionEvent e) {
+        e.getPresentation().setVisible(myBreakpointFactory.canAddBreakpoints());
+      }
+
+      @Override
+      public void actionPerformed(AnActionEvent e) {
+        myBreakpointFactory.addBreakpoint(getEventProject(e));
+      }
+    }
+
+    private static class MyBreakpointManagerListener implements BreakpointManagerListener {
+
+      private final BreakpointsListener myListener;
+      public BreakpointManager myBreakpointManager;
+
+
+      public MyBreakpointManagerListener(BreakpointsListener listener, BreakpointManager breakpointManager) {
+        myListener = listener;
+        myBreakpointManager = breakpointManager;
+      }
+
+      @Override
+      public void breakpointsChanged() {
+        myListener.breakpointsChanged();
+      }
+    }
+  }
+
+  public static class JavaDebuggerSettingsPanelProvider extends DebuggerSettingsPanelProvider {
+    public int getPriority() {
+      return 1;
+    }
+
+    @Override
+    public Configurable getRootConfigurable() {
+      return new DebuggerLaunchingConfigurable();
+    }
+
+    public Collection<? extends Configurable> getConfigurables() {
+      final ArrayList<Configurable> configurables = new ArrayList<Configurable>();
+      configurables.add(new DebuggerDataViewsConfigurable(null));
+      configurables.add(new DebuggerSteppingConfigurable());
+      configurables.add(new UserRenderersConfigurable(null));
+      configurables.add(new DebuggerHotswapConfigurable());
+      return configurables;
+    }
+
+    public void apply() {
+      NodeRendererSettings.getInstance().fireRenderersChanged();
+    }
+  }
+
+  public static Project getCurrentProject() {
+    //todo[nik] improve
+    Project project = PlatformDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext());
+    if (project != null) {
+      return project;
+    }
+    return ProjectManager.getInstance().getDefaultProject();
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/PositionHighlighter.java b/java/debugger/impl/src/com/intellij/debugger/ui/PositionHighlighter.java
new file mode 100644
index 0000000..1339e9c
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/PositionHighlighter.java
@@ -0,0 +1,443 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui;
+
+import com.intellij.codeInsight.daemon.impl.DaemonListeners;
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerInvocationUtil;
+import com.intellij.debugger.SourcePosition;
+import com.intellij.debugger.engine.DebugProcessEvents;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.events.DebuggerContextCommandImpl;
+import com.intellij.debugger.impl.*;
+import com.intellij.debugger.jdi.StackFrameProxyImpl;
+import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
+import com.intellij.debugger.ui.breakpoints.*;
+import com.intellij.openapi.actionSystem.ActionGroup;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.DefaultActionGroup;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.colors.EditorColorsManager;
+import com.intellij.openapi.editor.colors.EditorColorsScheme;
+import com.intellij.openapi.editor.ex.DocumentEx;
+import com.intellij.openapi.editor.markup.GutterIconRenderer;
+import com.intellij.openapi.editor.markup.RangeHighlighter;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Comparing;
+import com.intellij.openapi.util.Computable;
+import com.intellij.openapi.util.Key;
+import com.intellij.openapi.util.Pair;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiFile;
+import com.intellij.util.StringBuilderSpinAllocator;
+import com.intellij.xdebugger.impl.actions.ViewBreakpointsAction;
+import com.intellij.xdebugger.ui.DebuggerColors;
+import com.sun.jdi.event.Event;
+import com.sun.jdi.event.LocatableEvent;
+import com.sun.jdi.event.MethodEntryEvent;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: lex
+ * Date: Jul 9, 2003
+ * Time: 6:24:35 PM
+ * To change this template use Options | File Templates.
+ */
+public class PositionHighlighter {
+  private static final Key<Boolean> HIGHLIGHTER_USERDATA_KEY = new Key<Boolean>("HIGHLIGHTER_USERDATA_KEY");
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.PositionHighlighter");
+  private final Project myProject;
+  private DebuggerContextImpl myContext = DebuggerContextImpl.EMPTY_CONTEXT;
+  private SelectionDescription      mySelectionDescription = null;
+  private ExecutionPointDescription myExecutionPointDescription = null;
+
+  public PositionHighlighter(Project project, DebuggerStateManager stateManager) {
+    myProject = project;
+
+    stateManager.addListener(new DebuggerContextListener() {
+      public void changeEvent(DebuggerContextImpl newContext, int event) {
+        myContext = newContext;
+        if (event != DebuggerSession.EVENT_REFRESH_VIEWS_ONLY && event != DebuggerSession.EVENT_THREADS_REFRESH) {
+          refresh();
+        }
+      }
+    });
+  }
+
+  private void showLocationInEditor() {
+    myContext.getDebugProcess().getManagerThread().schedule(new ShowLocationCommand(myContext));
+  }
+
+  private void refresh() {
+    clearSelections();
+    final DebuggerSession session = myContext.getDebuggerSession();
+    if(session != null) {
+      switch(session.getState()) {
+        case DebuggerSession.STATE_PAUSED:
+          if(myContext.getFrameProxy() != null) {
+            showLocationInEditor();
+            return;
+          }
+          break;
+      }
+    }
+  }
+
+  protected static class ExecutionPointDescription extends SelectionDescription {
+    private RangeHighlighter myHighlighter;
+    private final int myLineIndex;
+
+    protected ExecutionPointDescription(Editor editor, int lineIndex) {
+      super(editor);
+      myLineIndex = lineIndex;
+    }
+
+    public void select() {
+      if(myIsActive) return;
+      myIsActive = true;
+      EditorColorsScheme scheme = EditorColorsManager.getInstance().getGlobalScheme();
+      myHighlighter = myEditor.getMarkupModel().addLineHighlighter(
+        myLineIndex,
+        DebuggerColors.EXECUTION_LINE_HIGHLIGHTERLAYER,
+        scheme.getAttributes(DebuggerColors.EXECUTIONPOINT_ATTRIBUTES)
+      );
+      adjustCounter(myEditor, 1);
+      myHighlighter.setErrorStripeTooltip(DebuggerBundle.message("position.highlighter.stripe.tooltip"));
+      myHighlighter.putUserData(HIGHLIGHTER_USERDATA_KEY, Boolean.TRUE);
+    }
+
+    private static void adjustCounter(@NotNull Editor editor, int increment) {
+      JComponent component = editor.getComponent();
+      Object o = component.getClientProperty(DaemonListeners.IGNORE_MOUSE_TRACKING);
+      Integer value = ((o instanceof Integer) ? (Integer)o : 0) + increment;
+      component.putClientProperty(DaemonListeners.IGNORE_MOUSE_TRACKING, value > 0 ? value : null);
+    }
+
+    public void remove() {
+      if(!myIsActive) return;
+      myIsActive = false;
+      adjustCounter(myEditor, -1);
+      if (myHighlighter != null) {
+        myHighlighter.dispose();
+        myHighlighter = null;
+      }
+    }
+
+    public RangeHighlighter getHighlighter() {
+      return myHighlighter;
+    }
+  }
+
+  protected abstract static class SelectionDescription {
+      protected Editor myEditor;
+      protected boolean myIsActive;
+
+      public SelectionDescription(Editor editor) {
+        myEditor = editor;
+      }
+
+      public abstract void select();
+      public abstract void remove();
+
+      public static ExecutionPointDescription createExecutionPoint(final Editor editor,
+                                                                   final int lineIndex) {
+        return new ExecutionPointDescription(editor, lineIndex);
+      }
+
+      public static SelectionDescription createSelection(final Editor editor, final int lineIndex) {
+        return new SelectionDescription(editor) {
+          public void select() {
+            if(myIsActive) return;
+            myIsActive = true;
+            DocumentEx doc = (DocumentEx)editor.getDocument();
+            editor.getSelectionModel().setSelection(
+              doc.getLineStartOffset(lineIndex),
+              doc.getLineEndOffset(lineIndex) + doc.getLineSeparatorLength(lineIndex)
+            );
+          }
+
+          public void remove() {
+            if(!myIsActive) return;
+            myIsActive = false;
+            myEditor.getSelectionModel().removeSelection();
+          }
+        };
+      }
+    }
+
+  private void showSelection(SourcePosition position) {
+    Editor editor = getEditor(position);
+    if(editor == null) {
+      return;
+    }
+    if (mySelectionDescription != null) {
+      mySelectionDescription.remove();
+    }
+    mySelectionDescription = SelectionDescription.createSelection(editor, position.getLine());
+    mySelectionDescription.select();
+  }
+
+  private void showExecutionPoint(final SourcePosition position, List<Pair<Breakpoint, Event>> events) {
+    if (myExecutionPointDescription != null) {
+      myExecutionPointDescription.remove();
+    }
+    int lineIndex = position.getLine();
+    Editor editor = getEditor(position);
+    if(editor == null) {
+      return;
+    }
+    myExecutionPointDescription = SelectionDescription.createExecutionPoint(editor, lineIndex);
+    myExecutionPointDescription.select();
+
+    RangeHighlighter highlighter = myExecutionPointDescription.getHighlighter();
+
+    if(highlighter != null) {
+      final List<Pair<Breakpoint, Event>> eventsOutOfLine = new ArrayList<Pair<Breakpoint, Event>>();
+
+      for (final Pair<Breakpoint, Event> eventDescriptor : events) {
+        final Breakpoint breakpoint = eventDescriptor.getFirst();
+        // filter breakpoints that do not match the event
+        if (breakpoint instanceof MethodBreakpoint) {
+          try {
+            if (!((MethodBreakpoint)breakpoint).matchesEvent((LocatableEvent)eventDescriptor.getSecond(), myContext.getDebugProcess())) {
+              continue;
+            }
+          }
+          catch (EvaluateException ignored) {
+          }
+        }
+        else if (breakpoint instanceof WildcardMethodBreakpoint) {
+          if (!((WildcardMethodBreakpoint)breakpoint).matchesEvent((LocatableEvent)eventDescriptor.getSecond())) {
+            continue;
+          }
+        }
+
+        if (breakpoint instanceof BreakpointWithHighlighter) {
+          if (((BreakpointWithHighlighter)breakpoint).isVisible() && breakpoint.isValid()) {
+            breakpoint.reload();
+            final SourcePosition sourcePosition = ((BreakpointWithHighlighter)breakpoint).getSourcePosition();
+            if (sourcePosition == null || sourcePosition.getLine() != lineIndex) {
+              eventsOutOfLine.add(eventDescriptor);
+            }
+          }
+        }
+        else {
+          eventsOutOfLine.add(eventDescriptor);
+        }
+      }
+
+      if(!eventsOutOfLine.isEmpty()) {
+        highlighter.setGutterIconRenderer(new MyGutterIconRenderer(eventsOutOfLine));
+      }
+    }
+  }
+
+  private Editor getEditor(SourcePosition position) {
+    final PsiFile psiFile = position.getFile();
+    Document doc = PsiDocumentManager.getInstance(myProject).getDocument(psiFile);
+    if (!psiFile.isValid()) {
+      return null;
+    }
+    final int lineIndex = position.getLine();
+    if (lineIndex < 0 || lineIndex > doc.getLineCount()) {
+      //LOG.assertTrue(false, "Incorrect lineIndex " + lineIndex + " in file " + psiFile.getName());
+      return null;
+    }
+    return position.openEditor(false);
+  }
+
+  private void clearSelections() {
+    if (mySelectionDescription != null || myExecutionPointDescription != null) {
+      ApplicationManager.getApplication().runReadAction(new Runnable() {
+        public void run() {
+          if (mySelectionDescription != null) {
+            mySelectionDescription.remove();
+            mySelectionDescription = null;
+          }
+          if (myExecutionPointDescription != null) {
+            myExecutionPointDescription.remove();
+            myExecutionPointDescription = null;
+          }
+        }
+      });
+    }
+  }
+
+
+  public void updateContextPointDescription() {
+    if(myContext.getDebuggerSession() == null) return;
+
+    showLocationInEditor();
+  }
+
+  private class ShowLocationCommand extends DebuggerContextCommandImpl {
+    private final DebuggerContextImpl myContext;
+
+    public ShowLocationCommand(DebuggerContextImpl context) {
+      super(context);
+      myContext = context;
+    }
+
+    public void threadAction() {
+      final SourcePosition contextPosition = myContext.getSourcePosition();
+      if (contextPosition == null) {
+        return;
+      }
+      
+      boolean isExecutionPoint = false;
+      try {
+        StackFrameProxyImpl frameProxy = myContext.getFrameProxy();
+        final ThreadReferenceProxyImpl thread = getSuspendContext().getThread();
+        isExecutionPoint = thread != null && frameProxy != null && frameProxy.equals(thread.frame(0));
+      }
+      catch(Throwable th) {
+        LOG.debug(th);
+      }
+
+      final List<Pair<Breakpoint, Event>> events = DebuggerUtilsEx.getEventDescriptors(getSuspendContext());
+
+      final SourcePosition position = ApplicationManager.getApplication().runReadAction(new Computable<SourcePosition>() {
+        public SourcePosition compute() {
+          Document document = PsiDocumentManager.getInstance(myProject).getDocument(contextPosition.getFile());
+          if(document != null) {
+            if(contextPosition.getLine() < 0 || contextPosition.getLine() >= document.getLineCount()) {
+              return SourcePosition.createFromLine(contextPosition.getFile(), 0);
+            }
+          }
+          return contextPosition;
+        }
+      });
+
+      if(isExecutionPoint) {
+        DebuggerInvocationUtil.swingInvokeLater(myProject, new Runnable() {
+          public void run() {
+            final SourcePosition highlightPosition = getHighlightPosition(events, position);
+            showExecutionPoint(highlightPosition, events);
+          }
+        });
+      }
+      else {
+        DebuggerInvocationUtil.swingInvokeLater(myProject, new Runnable() {
+          public void run() {
+            showSelection(position);
+          }
+        });
+      }
+    }
+
+    private SourcePosition getHighlightPosition(final List<Pair<Breakpoint, Event>> events, SourcePosition position) {
+      for (Iterator<Pair<Breakpoint, Event>> iterator = events.iterator(); iterator.hasNext();) {
+        final Pair<Breakpoint, Event> eventDescriptor = iterator.next();
+        final Breakpoint breakpoint = eventDescriptor.getFirst();
+        if(breakpoint instanceof LineBreakpoint) {
+          breakpoint.reload();
+          final SourcePosition breakPosition = ((BreakpointWithHighlighter)breakpoint).getSourcePosition();
+          if(breakPosition != null && breakPosition.getLine() != position.getLine()) {
+            position = SourcePosition.createFromLine(position.getFile(), breakPosition.getLine());
+          }
+        }
+        else if(breakpoint instanceof MethodBreakpoint) {
+          final MethodBreakpoint methodBreakpoint = (MethodBreakpoint)breakpoint;
+          methodBreakpoint.reload();
+          final SourcePosition breakPosition = methodBreakpoint.getSourcePosition();
+          final LocatableEvent event = (LocatableEvent)eventDescriptor.getSecond();
+          if(breakPosition != null && breakPosition.getFile().equals(position.getFile()) && breakPosition.getLine() != position.getLine() && event instanceof MethodEntryEvent) {
+            try {
+              if (methodBreakpoint.matchesEvent(event, myContext.getDebugProcess())) {
+                position = SourcePosition.createFromLine(position.getFile(), breakPosition.getLine());
+              }
+            }
+            catch (EvaluateException ignored) {
+            }
+          }
+        }
+      }
+      return position;
+    }
+  }
+
+  private class MyGutterIconRenderer extends GutterIconRenderer {
+    private final List<Pair<Breakpoint, Event>> myEventsOutOfLine;
+
+    public MyGutterIconRenderer(List<Pair<Breakpoint, Event>> eventsOutOfLine) {
+      myEventsOutOfLine = eventsOutOfLine;
+    }
+
+    @NotNull
+    public Icon getIcon() {
+      return myEventsOutOfLine.get(0).getFirst().getIcon();
+    }
+
+    public String getTooltipText() {
+      DebugProcessImpl debugProcess = myContext.getDebugProcess();
+      if (debugProcess == null) {
+        return null;
+      }
+      final StringBuilder buf = StringBuilderSpinAllocator.alloc();
+      try {
+        //noinspection HardCodedStringLiteral
+        buf.append("<html><body>");
+        for (Iterator<Pair<Breakpoint, Event>> iterator = myEventsOutOfLine.iterator(); iterator.hasNext();) {
+          Pair<Breakpoint, Event> eventDescriptor = iterator.next();
+          buf.append(((DebugProcessEvents)debugProcess).getEventText(eventDescriptor));
+          if(iterator.hasNext()) {
+            //noinspection HardCodedStringLiteral
+            buf.append("<br>");
+          }
+        }
+        //noinspection HardCodedStringLiteral
+        buf.append("</body></html>");
+        return buf.toString();
+      }
+      finally {
+        StringBuilderSpinAllocator.dispose(buf);
+      }
+    }
+
+    public ActionGroup getPopupMenuActions() {
+      DefaultActionGroup group = new DefaultActionGroup();
+      for (Pair<Breakpoint, Event> eventDescriptor : myEventsOutOfLine) {
+        Breakpoint breakpoint = eventDescriptor.getFirst();
+        AnAction viewBreakpointsAction = new ViewBreakpointsAction(breakpoint.getDisplayName(), breakpoint);
+        group.add(viewBreakpointsAction);
+      }
+
+      return group;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+      return obj instanceof MyGutterIconRenderer &&
+             Comparing.equal(getTooltipText(), ((MyGutterIconRenderer)obj).getTooltipText()) &&
+             Comparing.equal(getIcon(), ((MyGutterIconRenderer)obj).getIcon());
+    }
+
+    @Override
+    public int hashCode() {
+      return getIcon().hashCode();
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/RunHotswapDialog.java b/java/debugger/impl/src/com/intellij/debugger/ui/RunHotswapDialog.java
new file mode 100644
index 0000000..36a5351
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/RunHotswapDialog.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui;
+
+import com.intellij.CommonBundle;
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.debugger.settings.DebuggerSettings;
+import com.intellij.ide.util.ElementsChooser;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.MultiLineLabelUI;
+import com.intellij.ui.IdeBorderFactory;
+import com.intellij.util.ui.OptionsDialog;
+import com.intellij.util.ui.UIUtil;
+
+import javax.swing.*;
+import java.awt.*;
+import java.util.*;
+import java.util.List;
+
+/**
+ * User: lex
+ * Date: Oct 6, 2003
+ * Time: 5:58:17 PM
+ */
+
+
+
+public class RunHotswapDialog extends OptionsDialog {
+  private final JPanel myPanel;
+  private final ElementsChooser<SessionItem> myElementsChooser;
+  private final boolean myDisplayHangWarning;
+
+  public RunHotswapDialog(Project project, List<DebuggerSession> sessions, boolean displayHangWarning) {
+    super(project);
+    myDisplayHangWarning = displayHangWarning;
+    myPanel = new JPanel(new BorderLayout());
+    final List<SessionItem> items = new ArrayList<SessionItem>(sessions.size());
+    for (DebuggerSession session : sessions) {
+      items.add(new SessionItem(session));
+    }
+    Collections.sort(items, new Comparator<SessionItem>() {
+      public int compare(SessionItem debuggerSession, SessionItem debuggerSession1) {
+        return debuggerSession.getSession().getSessionName().compareTo(debuggerSession1.getSession().getSessionName());
+      }
+    });
+    myElementsChooser = new ElementsChooser<SessionItem>(items, true);
+    myPanel.setBorder(IdeBorderFactory.createEmptyBorder(10, 0, 5, 0));
+    //myElementsChooser.setBorder(IdeBorderFactory.createEmptyBorder(5, 0, 0, 0));
+    if (sessions.size() > 0) {
+      myElementsChooser.selectElements(items.subList(0, 1));
+    }
+    myPanel.add(myElementsChooser, BorderLayout.CENTER);
+    //myPanel.add(new JLabel("Choose debug sessions to reload classes:"), BorderLayout.NORTH);
+    if(sessions.size() == 1) {
+      setTitle(DebuggerBundle.message("hotswap.dialog.title.with.session", sessions.get(0).getSessionName()));
+      myPanel.setVisible(false);
+    }
+    else {
+      setTitle(DebuggerBundle.message("hotswap.dialog.title"));
+    }
+    setButtonsAlignment(SwingUtilities.CENTER);
+    this.init();
+  }
+
+  protected boolean isToBeShown() {
+    return DebuggerSettings.RUN_HOTSWAP_ASK.equals(DebuggerSettings.getInstance().RUN_HOTSWAP_AFTER_COMPILE);
+  }
+
+  protected void setToBeShown(boolean value, boolean onOk) {
+    if (value) {
+      DebuggerSettings.getInstance().RUN_HOTSWAP_AFTER_COMPILE = DebuggerSettings.RUN_HOTSWAP_ASK;
+    }
+    else {
+      if (onOk) {
+        DebuggerSettings.getInstance().RUN_HOTSWAP_AFTER_COMPILE = DebuggerSettings.RUN_HOTSWAP_ALWAYS;
+      }
+      else {
+        DebuggerSettings.getInstance().RUN_HOTSWAP_AFTER_COMPILE = DebuggerSettings.RUN_HOTSWAP_NEVER;
+      }
+    }
+  }
+
+  protected boolean shouldSaveOptionsOnCancel() {
+    return true;
+  }
+
+  protected Action[] createActions(){
+    setOKButtonText(CommonBundle.getYesButtonText());
+    setCancelButtonText(CommonBundle.getNoButtonText());
+    return new Action[]{getOKAction(), getCancelAction()};
+  }
+
+  protected JComponent createNorthPanel() {
+    JLabel label = new JLabel(DebuggerBundle.message("hotswap.dialog.run.prompt"));
+    JPanel panel = new JPanel(new BorderLayout());
+    panel.add(label, BorderLayout.CENTER);
+    Icon icon = UIUtil.getQuestionIcon();
+    if (icon != null) {
+      label.setIcon(icon);
+      label.setIconTextGap(7);
+    }
+    if (myDisplayHangWarning) {
+      final JLabel warningLabel = new JLabel("WARNING! " + DebuggerBundle.message("hotswap.dialog.hang.warning"));
+      warningLabel.setUI(new MultiLineLabelUI());
+      panel.add(warningLabel, BorderLayout.SOUTH);
+    }
+    return panel;
+  }
+
+  protected JComponent createCenterPanel() {
+    return myPanel;
+  }
+
+  public Collection<DebuggerSession> getSessionsToReload() {
+    final List<SessionItem> markedElements = myElementsChooser.getMarkedElements();
+    final List<DebuggerSession>  sessions = new ArrayList<DebuggerSession>(markedElements.size());
+    for (SessionItem item : markedElements) {
+      sessions.add(item.getSession());
+    }
+    return sessions;
+  }
+
+  private static class SessionItem {
+    private final DebuggerSession mySession;
+
+    public SessionItem(DebuggerSession session) {
+      mySession = session;
+    }
+
+    public DebuggerSession getSession() {
+      return mySession;
+    }
+
+    public String toString() {
+      return mySession.getSessionName();
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/StatementEvaluationDialog.java b/java/debugger/impl/src/com/intellij/debugger/ui/StatementEvaluationDialog.java
new file mode 100644
index 0000000..b8de25a
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/StatementEvaluationDialog.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerInvocationUtil;
+import com.intellij.debugger.HelpID;
+import com.intellij.debugger.actions.EvaluateActionHandler;
+import com.intellij.debugger.engine.evaluation.CodeFragmentFactory;
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.debugger.impl.PositionUtil;
+import com.intellij.debugger.settings.DebuggerSettings;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.CustomShortcutSet;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.event.DocumentAdapter;
+import com.intellij.openapi.editor.event.DocumentEvent;
+import com.intellij.openapi.help.HelpManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.Splitter;
+import com.intellij.openapi.util.DimensionService;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiWhiteSpace;
+import org.jetbrains.annotations.NonNls;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+
+/**
+ * @author lex
+ */
+public class StatementEvaluationDialog extends EvaluationDialog{
+  private final JPanel myPanel;
+  private final Action mySwitchAction = new SwitchAction();
+  private static final @NonNls String STATEMENT_EDITOR_DIMENSION_KEY = "#com.intellij.debugger.ui.StatementEvaluationDialog.StatementEditor";
+  private static final @NonNls String EVALUATION_PANEL_DIMENSION_KEY = "#com.intellij.debugger.ui.StatementEvaluationDialog.EvaluationPanel";
+
+  public StatementEvaluationDialog(final Project project, TextWithImports text) {
+    super(project, text);
+    setTitle(DebuggerBundle.message("evaluate.statement.dialog.title"));
+    myPanel = new JPanel(new BorderLayout());
+
+    final Splitter splitter = new Splitter(true);
+    splitter.setHonorComponentsMinimumSize(true);
+
+    final JPanel editorPanel = new JPanel(new GridBagLayout());
+
+    final JLabel statementsLabel = new JLabel(DebuggerBundle.message("label.evaluation.dialog.statements"));
+    editorPanel.add(statementsLabel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 2, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 0, 0, 0), 0, 0));
+    editorPanel.add(getStatementEditor(), new GridBagConstraints(0, GridBagConstraints.RELATIVE, 2, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(2, 0, 0, 0), 0, 0));
+
+    splitter.setFirstComponent(editorPanel);
+
+    final MyEvaluationPanel evaluationPanel = getEvaluationPanel();
+    final JPanel ep = new JPanel(new BorderLayout());
+    //final JLabel resultLabel = new JLabel(DebuggerBundle.message("label.evaluate.dialog.result"));
+    //ep.add(resultLabel, BorderLayout.NORTH);
+    ep.add(evaluationPanel, BorderLayout.CENTER);
+    splitter.setSecondComponent(ep);
+    final Dimension statementSize = DimensionService.getInstance().getSize(STATEMENT_EDITOR_DIMENSION_KEY, project);
+    final Dimension evaluationSize = DimensionService.getInstance().getSize(EVALUATION_PANEL_DIMENSION_KEY, project);
+    if (statementSize != null && evaluationSize != null) {
+      final float proportion = (float)statementSize.height / (float)(statementSize.height + evaluationSize.height);
+      splitter.setProportion(proportion);
+    }
+    myPanel.add(splitter, BorderLayout.CENTER);
+
+    setDebuggerContext(getDebuggerContext());
+
+    final KeyStroke codeFragment = KeyStroke.getKeyStroke(KeyEvent.VK_E,     KeyEvent.ALT_MASK);
+    final KeyStroke resultStroke = KeyStroke.getKeyStroke(KeyEvent.VK_R,     KeyEvent.ALT_MASK);
+    final KeyStroke altEnter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, KeyEvent.CTRL_MASK);
+
+    final JRootPane rootPane = getRootPane();
+    final AnAction toStatementAction = new AnAction() {
+      public void actionPerformed(AnActionEvent e) {
+        getStatementEditor().requestFocus();
+      }
+    };
+    toStatementAction.registerCustomShortcutSet(new CustomShortcutSet(codeFragment), rootPane);
+    addDisposeRunnable(new Runnable() {
+      public void run() {
+        toStatementAction.unregisterCustomShortcutSet(rootPane);
+      }
+    });
+
+    final AnAction toEvaluationAction = new AnAction() {
+      public void actionPerformed(AnActionEvent e) {
+        getEvaluationPanel().getWatchTree().requestFocus();
+      }
+    };
+    toEvaluationAction.registerCustomShortcutSet(new CustomShortcutSet(resultStroke), rootPane);
+    addDisposeRunnable(new Runnable() {
+      public void run() {
+        toEvaluationAction.unregisterCustomShortcutSet(rootPane);
+      }
+    });
+
+    final AnAction okAction = new AnAction() {
+      public void actionPerformed(AnActionEvent e) {
+        doOKAction();
+      }
+    };
+    okAction.registerCustomShortcutSet(new CustomShortcutSet(altEnter), rootPane);
+    addDisposeRunnable(new Runnable() {
+      public void run() {
+        okAction.unregisterCustomShortcutSet(rootPane);
+      }
+    });
+
+    final DebuggerEditorImpl editor = getEditor();
+    final DocumentAdapter docListener = new DocumentAdapter() {
+      public void documentChanged(final DocumentEvent e) {
+        DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
+          public void run() {
+            updateSwitchButton(e.getDocument());
+          }
+        });
+      }
+    };
+    editor.addDocumentListener(docListener);
+    addDisposeRunnable(new Runnable() {
+      public void run() {
+        editor.removeDocumentListener(docListener);
+      }
+    });
+
+    init();
+  }
+
+  private void updateSwitchButton(Document document) {
+    PsiDocumentManager.getInstance(getProject()).commitDocument(document);
+    PsiFile psiFile = PsiDocumentManager.getInstance(getProject()).getPsiFile(document);
+    if (psiFile == null) {
+      return;
+    }
+    PsiElement[] children = psiFile.getChildren();
+    int nonWhite = 0;
+    for (PsiElement child : children) {
+      if (!(child instanceof PsiWhiteSpace)) {
+        nonWhite++;
+        if (nonWhite > 1) {
+          mySwitchAction.setEnabled(false);
+          return;
+        }
+      }
+    }
+
+    mySwitchAction.setEnabled(true);
+  }
+
+  protected Action[] createActions(){
+    return new Action[]{getOKAction(), getCancelAction(), mySwitchAction, getHelpAction() };
+  }
+
+  protected void doHelpAction() {
+    HelpManager.getInstance().invokeHelp(HelpID.EVALUATE);
+  }
+
+  protected DebuggerEditorImpl createEditor(final CodeFragmentFactory factory) {
+    return new DebuggerStatementEditor(getProject(), PositionUtil.getContextElement(getDebuggerContext()), "evaluation", factory);
+  }
+
+  public void dispose() {
+    try {
+      final DebuggerEditorImpl editor = getEditor();
+      final DimensionService dimensionService = DimensionService.getInstance();
+      dimensionService.setSize(STATEMENT_EDITOR_DIMENSION_KEY, editor.getSize(null), getProject());
+      dimensionService.setSize(EVALUATION_PANEL_DIMENSION_KEY, getEvaluationPanel().getSize(), getProject());
+    }
+    finally {
+      super.dispose();
+    }
+  }
+
+  protected JComponent createCenterPanel() {
+    return myPanel;
+  }
+
+  private DebuggerStatementEditor getStatementEditor() {
+    return (DebuggerStatementEditor)getEditor();
+  }
+
+  private class SwitchAction extends AbstractAction {
+    public SwitchAction() {
+      putValue(NAME, DebuggerBundle.message("action.evaluate.statement.dialog.switch.mode.description"));
+    }
+
+    public void actionPerformed(ActionEvent e) {
+      final TextWithImports text = getEditor().getText();
+      doCancelAction();
+      DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
+        public void run() {
+          EvaluateActionHandler.showEvaluationDialog(getProject(), text, DebuggerSettings.EVALUATE_EXPRESSION);
+        }
+      });
+    }
+  }
+
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/ValueHint.java b/java/debugger/impl/src/com/intellij/debugger/ui/ValueHint.java
new file mode 100644
index 0000000..f825e83
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/ValueHint.java
@@ -0,0 +1,317 @@
+/*
+ * Copyright 2000-2011 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.debugger.ui;
+
+import com.intellij.codeInsight.hint.HintUtil;
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerInvocationUtil;
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.JVMName;
+import com.intellij.debugger.engine.JVMNameUtil;
+import com.intellij.debugger.engine.evaluation.*;
+import com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilderImpl;
+import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator;
+import com.intellij.debugger.engine.events.DebuggerContextCommandImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.impl.EditorTextProvider;
+import com.intellij.debugger.ui.impl.DebuggerTreeRenderer;
+import com.intellij.debugger.ui.impl.InspectDebuggerTree;
+import com.intellij.debugger.ui.impl.watch.WatchItemDescriptor;
+import com.intellij.debugger.ui.tree.render.DescriptorLabelListener;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.*;
+import com.intellij.psi.*;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.ui.SimpleColoredText;
+import com.intellij.ui.SimpleTextAttributes;
+import com.intellij.util.IncorrectOperationException;
+import com.intellij.xdebugger.impl.evaluate.quick.common.AbstractValueHint;
+import com.intellij.xdebugger.impl.evaluate.quick.common.AbstractValueHintTreeComponent;
+import com.intellij.xdebugger.impl.evaluate.quick.common.ValueHintType;
+import com.sun.jdi.Method;
+import com.sun.jdi.PrimitiveValue;
+import com.sun.jdi.Value;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.awt.*;
+
+/**
+ * @author lex
+ * @since Nov 24, 2003
+ */
+public class ValueHint extends AbstractValueHint {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.ValueHint");
+  private PsiElement myCurrentExpression = null;
+  private Value myValueToShow = null;
+
+  private ValueHint(Project project, Editor editor, Point point, ValueHintType type, final PsiElement selectedExpression, final TextRange textRange) {
+    super(project, editor, point, type, textRange);
+    myCurrentExpression = selectedExpression;
+  }
+
+  public static ValueHint createValueHint(Project project, Editor editor, Point point, ValueHintType type) {
+    Trinity<PsiElement, TextRange, Value> trinity = getSelectedExpression(project, editor, point, type);
+    final ValueHint hint = new ValueHint(project, editor, point, type, trinity.getFirst(), trinity.getSecond());
+    hint.myValueToShow = trinity.getThird();
+    return hint;
+  }
+
+  protected boolean canShowHint() {
+    return myCurrentExpression != null;
+  }
+
+
+  @Nullable
+  private ExpressionEvaluator getExpressionEvaluator(DebuggerContextImpl debuggerContext) throws EvaluateException {
+    if (myCurrentExpression instanceof PsiExpression) {
+      return EvaluatorBuilderImpl.getInstance().build(myCurrentExpression, debuggerContext.getSourcePosition());
+    }
+
+    CodeFragmentFactory factory = DebuggerUtilsEx.getEffectiveCodeFragmentFactory(myCurrentExpression);
+    TextWithImportsImpl textWithImports = new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, myCurrentExpression.getText());
+    if (factory == null) return null;
+    JavaCodeFragment codeFragment = factory.createCodeFragment(textWithImports, myCurrentExpression.getContext(), getProject());
+    codeFragment.forceResolveScope(GlobalSearchScope.allScope(getProject()));
+    return factory.getEvaluatorBuilder().build(codeFragment, debuggerContext.getSourcePosition());
+  }
+
+
+  protected void evaluateAndShowHint() {
+    final DebuggerContextImpl debuggerContext = DebuggerManagerEx.getInstanceEx(getProject()).getContext();
+
+    final DebuggerSession debuggerSession = debuggerContext.getDebuggerSession();
+    if(debuggerSession == null || !debuggerSession.isPaused()) return;
+
+    try {
+
+      final ExpressionEvaluator evaluator = getExpressionEvaluator(debuggerContext);
+      if (evaluator == null) return;
+
+      debuggerContext.getDebugProcess().getManagerThread().schedule(new DebuggerContextCommandImpl(debuggerContext) {
+        public Priority getPriority() {
+          return Priority.HIGH;
+        }
+
+        public void threadAction() {
+          try {
+            final EvaluationContextImpl evaluationContext = debuggerContext.createEvaluationContext();
+
+            final String expressionText = ApplicationManager.getApplication().runReadAction(new Computable<String>() {
+              public String compute() {
+                return myCurrentExpression.getText();
+              }
+            });
+            final TextWithImports text = new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, expressionText);
+            final Value value = myValueToShow != null? myValueToShow : evaluator.evaluate(evaluationContext);
+
+            final WatchItemDescriptor descriptor = new WatchItemDescriptor(getProject(), text, value);
+            if (!isActiveTooltipApplicable(value) || getType() == ValueHintType.MOUSE_OVER_HINT) {
+              if (getType() == ValueHintType.MOUSE_OVER_HINT) {
+                // force using default renderer for mouse over hint in order to not to call accidentally methods while rendering
+                // otherwise, if the hint is invoked explicitly, show it with the right "auto" renderer
+                descriptor.setRenderer(DebugProcessImpl.getDefaultRenderer(value));
+              }
+              descriptor.updateRepresentation(evaluationContext, new DescriptorLabelListener() {
+                public void labelChanged() {
+                  if(getCurrentRange() != null) {
+                    if(getType() != ValueHintType.MOUSE_OVER_HINT || descriptor.isValueValid()) {
+                      final SimpleColoredText simpleColoredText = DebuggerTreeRenderer.getDescriptorText(debuggerContext, descriptor, true);
+                      if (isActiveTooltipApplicable(value)){
+                        simpleColoredText.append(" (" + DebuggerBundle.message("active.tooltip.suggestion") + ")", SimpleTextAttributes.GRAYED_ATTRIBUTES);
+                      }
+                      showHint(simpleColoredText, descriptor);
+                    }
+                  }
+                }
+              });
+            } else {
+              final InspectDebuggerTree tree = getInspectTree(descriptor);
+              showTreePopup(tree, debuggerContext, expressionText, new ValueHintTreeComponent(ValueHint.this, tree, expressionText));
+            }
+          }
+          catch (EvaluateException e) {
+            LOG.debug(e);
+          }
+        }
+
+      });
+    }
+    catch (EvaluateException e) {
+      LOG.debug(e);
+    }
+  }
+
+  private static boolean isActiveTooltipApplicable(final Value value) {
+    return value != null && !(value instanceof PrimitiveValue);
+  }
+
+  public void showTreePopup(final InspectDebuggerTree tree,
+                        final DebuggerContextImpl debuggerContext,
+                        final String title,
+                        final AbstractValueHintTreeComponent<?> component) {
+    DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
+      public void run() {
+        tree.rebuild(debuggerContext);
+        showTreePopup(component, tree, title);
+      }
+    });
+  }
+
+  private void showHint(final SimpleColoredText text, final WatchItemDescriptor descriptor) {
+    DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
+      public void run() {
+        if(!isHintHidden()) {
+          JComponent component;
+          if (!isActiveTooltipApplicable(descriptor.getValue())) {
+            component = HintUtil.createInformationLabel(text);
+          }
+          else {
+            component = createExpandableHintComponent(text, new Runnable() {
+              public void run() {
+                final DebuggerContextImpl debuggerContext = DebuggerManagerEx.getInstanceEx(getProject()).getContext();
+                final DebugProcessImpl debugProcess = debuggerContext.getDebugProcess();
+                debugProcess.getManagerThread().schedule(new DebuggerContextCommandImpl(debuggerContext) {
+                              public void threadAction() {
+                                descriptor.setRenderer(debugProcess.getAutoRenderer(descriptor));
+                                final InspectDebuggerTree tree = getInspectTree(descriptor);
+                                final String expressionText = ApplicationManager.getApplication().runReadAction(new Computable<String>() {
+                                  @Override
+                                  public String compute() {
+                                    return myCurrentExpression.getText();
+                                  }
+                                });
+                                showTreePopup(tree, debuggerContext, expressionText,
+                                              new ValueHintTreeComponent(ValueHint.this, tree, expressionText));
+                              }
+                            });
+              }
+            });
+          }
+          if (!showHint(component)) return;
+          if(getType() == ValueHintType.MOUSE_CLICK_HINT) {
+            HintUtil.createInformationLabel(text).requestFocusInWindow();
+          }
+        }
+      }
+    });
+  }
+
+  private InspectDebuggerTree getInspectTree(final WatchItemDescriptor descriptor) {
+    final InspectDebuggerTree tree = new InspectDebuggerTree(getProject());
+    tree.getModel().addTreeModelListener(createTreeListener(tree));
+    tree.setInspectDescriptor(descriptor);
+    return tree;
+  }
+
+  @Nullable
+  private static Pair<PsiElement, TextRange> findExpression(PsiElement element, boolean allowMethodCalls) {
+    final EditorTextProvider textProvider = EditorTextProvider.EP.forLanguage(element.getLanguage());
+    if (textProvider != null) {
+      return textProvider.findExpression(element, allowMethodCalls);
+    }
+    return null;
+  }
+
+  private static Trinity<PsiElement, TextRange, Value> getSelectedExpression(final Project project, final Editor editor, final Point point, final ValueHintType type) {
+    final Ref<PsiElement> selectedExpression = Ref.create(null);
+    final Ref<TextRange> currentRange = Ref.create(null);
+    final Ref<Value> preCalculatedValue = Ref.create(null);
+
+    PsiDocumentManager.getInstance(project).commitAndRunReadAction(new Runnable() {
+      public void run() {
+        // Point -> offset
+        final int offset = calculateOffset(editor, point);
+
+
+        PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
+
+        if(psiFile == null || !psiFile.isValid()) {
+          return;
+        }
+
+        int selectionStart = editor.getSelectionModel().getSelectionStart();
+        int selectionEnd   = editor.getSelectionModel().getSelectionEnd();
+
+        if((type == ValueHintType.MOUSE_CLICK_HINT || type == ValueHintType.MOUSE_ALT_OVER_HINT) && (selectionStart <= offset && offset <= selectionEnd)) {
+          PsiElement ctx = (selectionStart > 0) ? psiFile.findElementAt(selectionStart - 1) : psiFile.findElementAt(selectionStart);
+          try {
+            String text = editor.getSelectionModel().getSelectedText();
+            if(text != null && ctx != null) {
+              final JVMElementFactory factory = JVMElementFactories.getFactory(ctx.getLanguage(), project);
+              if (factory == null) {
+                return;
+              }
+              selectedExpression.set(factory.createExpressionFromText(text, ctx));
+              currentRange.set(new TextRange(editor.getSelectionModel().getSelectionStart(), editor.getSelectionModel().getSelectionEnd()));
+            }
+          }
+          catch (IncorrectOperationException ignored) {
+          }
+        }
+
+        if(currentRange.get() == null) {
+          PsiElement elementAtCursor = psiFile.findElementAt(offset);
+          if (elementAtCursor == null) {
+            return;
+          }
+          Pair<PsiElement, TextRange> pair = findExpression(elementAtCursor, type == ValueHintType.MOUSE_CLICK_HINT || type == ValueHintType.MOUSE_ALT_OVER_HINT);
+          if (pair == null) {
+            if (type == ValueHintType.MOUSE_OVER_HINT) {
+              final DebuggerSession debuggerSession = DebuggerManagerEx.getInstanceEx(project).getContext().getDebuggerSession();
+              if(debuggerSession != null && debuggerSession.isPaused()) {
+                final Pair<Method, Value> lastExecuted = debuggerSession.getProcess().getLastExecutedMethod();
+                if (lastExecuted != null) {
+                  final Method method = lastExecuted.getFirst();
+                  if (method != null) {
+                    final Pair<PsiElement, TextRange> expressionPair = findExpression(elementAtCursor, true);
+                    if (expressionPair != null && expressionPair.getFirst() instanceof PsiMethodCallExpression) {
+                      final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expressionPair.getFirst();
+                      final PsiMethod psiMethod = methodCallExpression.resolveMethod();
+                      if (psiMethod != null) {
+                        final JVMName jvmSignature = JVMNameUtil.getJVMSignature(psiMethod);
+                        try {
+                          if (method.name().equals(psiMethod.getName()) && method.signature().equals(jvmSignature.getName(debuggerSession.getProcess()))) {
+                            pair = expressionPair;
+                            preCalculatedValue.set(lastExecuted.getSecond());
+                          }
+                        }
+                        catch (EvaluateException ignored) {
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+          if (pair == null) {
+            return;
+          }
+          selectedExpression.set(pair.getFirst());
+          currentRange.set(pair.getSecond());
+        }
+      }
+    });
+    return Trinity.create(selectedExpression.get(), currentRange.get(), preCalculatedValue.get());
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/ValueHintTreeComponent.java b/java/debugger/impl/src/com/intellij/debugger/ui/ValueHintTreeComponent.java
new file mode 100644
index 0000000..9902dfc
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/ValueHintTreeComponent.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui;
+
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.debugger.engine.events.DebuggerContextCommandImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.ui.impl.InspectDebuggerTree;
+import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeExpression;
+import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
+import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.Pair;
+import com.intellij.xdebugger.impl.evaluate.quick.common.AbstractValueHintTreeComponent;
+
+/**
+ * @author nik
+*/
+class ValueHintTreeComponent extends AbstractValueHintTreeComponent<Pair<NodeDescriptorImpl, String>> {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.ValueHintTreeComponent");
+  private final ValueHint myValueHint;
+  private final InspectDebuggerTree myTree;
+
+  public ValueHintTreeComponent(final ValueHint valueHint, InspectDebuggerTree tree, final String title) {
+    super(valueHint, tree, Pair.create(tree.getInspectDescriptor(), title));
+    myValueHint = valueHint;
+    myTree = tree;
+  }
+
+
+  protected void updateTree(Pair<NodeDescriptorImpl, String> descriptorWithTitle){
+    final NodeDescriptorImpl descriptor = descriptorWithTitle.first;
+    final String title = descriptorWithTitle.second;
+    final DebuggerContextImpl context = (DebuggerManagerEx.getInstanceEx(myValueHint.getProject())).getContext();
+    context.getDebugProcess().getManagerThread().schedule(new DebuggerContextCommandImpl(context) {
+      public void threadAction() {
+        myTree.setInspectDescriptor(descriptor);
+        myValueHint.showTreePopup(myTree, context, title, ValueHintTreeComponent.this);
+      }
+    });
+  }
+
+
+  protected void setNodeAsRoot(final Object node) {
+    if (node instanceof DebuggerTreeNodeImpl) {
+      myValueHint.shiftLocation();
+      final DebuggerTreeNodeImpl debuggerTreeNode = (DebuggerTreeNodeImpl)node;
+      final DebuggerContextImpl context = (DebuggerManagerEx.getInstanceEx(myValueHint.getProject())).getContext();
+      context.getDebugProcess().getManagerThread().schedule(new DebuggerContextCommandImpl(context) {
+        public void threadAction() {
+          try {
+            final NodeDescriptorImpl descriptor = debuggerTreeNode.getDescriptor();
+            final TextWithImports evaluationText = DebuggerTreeNodeExpression.createEvaluationText(debuggerTreeNode, context);
+            final String title = evaluationText.getText();
+            addToHistory(Pair.create(descriptor, title));
+            myTree.setInspectDescriptor(descriptor);
+            myValueHint.showTreePopup(myTree, context, title, ValueHintTreeComponent.this);
+          }
+          catch (final EvaluateException e1) {
+            LOG.debug(e1);
+          }
+        }
+      });
+    }
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/WeakMouseListener.java b/java/debugger/impl/src/com/intellij/debugger/ui/WeakMouseListener.java
new file mode 100644
index 0000000..c4b5ed0
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/WeakMouseListener.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui;
+
+import com.intellij.util.WeakListener;
+
+import javax.swing.*;
+import java.awt.event.MouseListener;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: Dec 25, 2004
+ */
+public class WeakMouseListener extends WeakListener<JComponent, MouseListener> {
+  public WeakMouseListener(JComponent source, MouseListener listenerImpl) {
+    super(source, MouseListener.class, listenerImpl);
+  }
+  public void addListener(JComponent source, MouseListener listener) {
+    source.addMouseListener(listener);
+  }
+  public void removeListener(JComponent source, MouseListener listener) {
+    source.removeMouseListener(listener);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/WeakMouseMotionListener.java b/java/debugger/impl/src/com/intellij/debugger/ui/WeakMouseMotionListener.java
new file mode 100644
index 0000000..94eb402
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/WeakMouseMotionListener.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui;
+
+import com.intellij.util.WeakListener;
+
+import javax.swing.*;
+import java.awt.event.MouseMotionListener;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: Dec 25, 2004
+ */
+public class WeakMouseMotionListener extends WeakListener<JComponent, MouseMotionListener> {
+  public WeakMouseMotionListener(JComponent source, MouseMotionListener listenerImpl) {
+    super(source, MouseMotionListener.class, listenerImpl);
+  }
+  public void addListener(JComponent source, MouseMotionListener listener) {
+    source.addMouseMotionListener(listener);
+  }
+  public void removeListener(JComponent source, MouseMotionListener listener) {
+    source.removeMouseMotionListener(listener);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointCategoryGroup.java b/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointCategoryGroup.java
new file mode 100644
index 0000000..032b480
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointCategoryGroup.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2000-2012 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.debugger.ui;
+
+import com.intellij.debugger.ui.breakpoints.Breakpoint;
+import com.intellij.debugger.ui.breakpoints.BreakpointFactory;
+import com.intellij.openapi.util.Key;
+import com.intellij.xdebugger.breakpoints.ui.XBreakpointGroup;
+import com.intellij.xdebugger.impl.breakpoints.ui.grouping.XBreakpointTypeGroup;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: zajac
+ * Date: 23.05.12
+ * Time: 16:22
+ * To change this template use File | Settings | File Templates.
+ */
+public class XBreakpointCategoryGroup extends XBreakpointGroup {
+  private Key<? extends Breakpoint> myCategory;
+  private Icon myIcon;
+  private final String myName;
+
+  public XBreakpointCategoryGroup(BreakpointFactory factory) {
+    myCategory = factory.getBreakpointCategory();
+    myIcon = factory.getIcon();
+    final String name = factory.getDisplayName();
+    myName = name != null ? name : "UNKNOWN";
+  }
+
+  public Key<? extends Breakpoint> getCategory() {
+    return myCategory;
+  }
+
+  @Override
+  public Icon getIcon(boolean isOpen) {
+    return myIcon;
+  }
+
+  @NotNull
+  @Override
+  public String getName() {
+    return myName;
+  }
+
+  @Override
+  public int compareTo(XBreakpointGroup o) {
+    if (o instanceof XBreakpointTypeGroup) {
+      return -1;
+    }
+    if (o instanceof XBreakpointCategoryGroup) {
+      return getFactoryIndex() - ((XBreakpointCategoryGroup)o).getFactoryIndex();
+    }
+    return super.compareTo(o);
+  }
+
+  private int getFactoryIndex() {
+    BreakpointFactory[] breakpointFactories = BreakpointFactory.getBreakpointFactories();
+    for (int i = 0; i < breakpointFactories.length; ++i) {
+      if (breakpointFactories[i].getBreakpointCategory().equals(myCategory)) {
+        return i;
+      }
+    }
+    return -1;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointClassGroup.java b/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointClassGroup.java
new file mode 100644
index 0000000..5a81258
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointClassGroup.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2000-2012 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.debugger.ui;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.util.PlatformIcons;
+import com.intellij.xdebugger.breakpoints.ui.XBreakpointGroup;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+
+public class XBreakpointClassGroup extends XBreakpointGroup {
+  private static final String DEFAULT_PACKAGE_NAME = DebuggerBundle.message("default.package.name");
+
+  private String myPackageName;
+  private String myClassName;
+
+  public XBreakpointClassGroup(@Nullable String packageName, String className) {
+    myPackageName = packageName != null ? packageName : DEFAULT_PACKAGE_NAME;
+    myClassName = className;
+  }
+
+  @Override
+  public Icon getIcon(boolean isOpen) {
+    return PlatformIcons.CLASS_ICON;
+  }
+
+  @NotNull
+  @Override
+  public String getName() {
+    return getClassName();
+  }
+
+  @NotNull
+  public String getPackageName() {
+    return myPackageName;
+  }
+
+  @NotNull
+  public String getClassName() {
+    return myClassName;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointGroupingByCategoryRule.java b/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointGroupingByCategoryRule.java
new file mode 100644
index 0000000..f3cf9b9
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointGroupingByCategoryRule.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2000-2012 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.debugger.ui;
+
+import com.intellij.debugger.ui.breakpoints.AnyExceptionBreakpoint;
+import com.intellij.debugger.ui.breakpoints.Breakpoint;
+import com.intellij.debugger.ui.breakpoints.BreakpointFactory;
+import com.intellij.debugger.ui.breakpoints.ExceptionBreakpoint;
+import com.intellij.openapi.util.Key;
+import com.intellij.xdebugger.breakpoints.ui.XBreakpointGroupingRule;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collection;
+
+class XBreakpointGroupingByCategoryRule<B> extends XBreakpointGroupingRule<B, XBreakpointCategoryGroup> {
+  XBreakpointGroupingByCategoryRule() {
+    super("XBreakpointGroupingByCategoryRule", "Type");
+  }
+
+  @Override
+  public boolean isAlwaysEnabled() {
+    return true;
+  }
+
+  @Override
+  public XBreakpointCategoryGroup getGroup(@NotNull B b, @NotNull Collection<XBreakpointCategoryGroup> groups) {
+    if (b instanceof Breakpoint) {
+      final Breakpoint breakpoint = (Breakpoint)b;
+      Key<? extends Breakpoint> category = breakpoint.getCategory();
+      if (category.equals(AnyExceptionBreakpoint.ANY_EXCEPTION_BREAKPOINT)) {
+        category = ExceptionBreakpoint.CATEGORY;
+      }
+      for (XBreakpointCategoryGroup group : groups) {
+        if (group.getCategory().equals(category)) {
+          return group;
+        }
+      }
+      final BreakpointFactory factory = BreakpointFactory.getInstance(category);
+      if (factory != null) {
+        return new XBreakpointCategoryGroup(factory);
+      }
+    }
+    return null;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointGroupingByClassRule.java b/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointGroupingByClassRule.java
new file mode 100644
index 0000000..aa28158
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointGroupingByClassRule.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2000-2012 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.debugger.ui;
+
+import com.intellij.debugger.ui.breakpoints.Breakpoint;
+import com.intellij.debugger.ui.breakpoints.BreakpointFactory;
+import com.intellij.xdebugger.breakpoints.ui.XBreakpointGroupingRule;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collection;
+
+class XBreakpointGroupingByClassRule<B> extends XBreakpointGroupingRule<B, XBreakpointClassGroup> {
+  XBreakpointGroupingByClassRule() {
+    super("XBreakpointGroupingByClassRule", "Group by Class");
+  }
+
+  @Override
+  public boolean isAlwaysEnabled() {
+    return false;
+  }
+
+  @Override
+  public XBreakpointClassGroup getGroup(@NotNull B b, @NotNull Collection<XBreakpointClassGroup> groups) {
+    if (b instanceof Breakpoint) {
+      final Breakpoint breakpoint = (Breakpoint)b;
+      String className = breakpoint.getShortClassName();
+      String packageName = breakpoint.getPackageName();
+      if (className == null) {
+        return null;
+      }
+      for (XBreakpointClassGroup group : groups) {
+        if (group.getClassName().equals(className) && group.getPackageName().equals(packageName))  {
+          return group;
+        }
+      }
+      return new XBreakpointClassGroup(packageName, className);
+    }
+    return null;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointGroupingByPackageRule.java b/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointGroupingByPackageRule.java
new file mode 100644
index 0000000..a9f43cc
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointGroupingByPackageRule.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2000-2012 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.debugger.ui;
+
+import com.intellij.debugger.ui.breakpoints.BreakpointWithHighlighter;
+import com.intellij.debugger.ui.breakpoints.ExceptionBreakpoint;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.xdebugger.breakpoints.ui.XBreakpointGroup;
+import com.intellij.xdebugger.breakpoints.ui.XBreakpointGroupingRule;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collection;
+
+public class XBreakpointGroupingByPackageRule<B> extends XBreakpointGroupingRule<B, XBreakpointPackageGroup> {
+
+  protected XBreakpointGroupingByPackageRule() {
+    super("XBreakpointGroupingByPackageRule", "Group by package");
+  }
+
+  @Override
+  public XBreakpointPackageGroup getGroup(@NotNull B breakpoint, @NotNull Collection<XBreakpointPackageGroup> groups) {
+    String packageName = null;
+    if (breakpoint instanceof BreakpointWithHighlighter) {
+      packageName = ((BreakpointWithHighlighter)breakpoint).getPackageName();
+    }
+    else if (breakpoint instanceof ExceptionBreakpoint) {
+      packageName = ((ExceptionBreakpoint)breakpoint).getPackageName();
+    }
+    if (packageName == null) {
+      return null;
+    }
+    for (XBreakpointPackageGroup group : groups) {
+      if (StringUtil.equals(group.getPackageName(), packageName)) {
+        return group;
+      }
+    }
+    return new XBreakpointPackageGroup(packageName);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointPackageGroup.java b/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointPackageGroup.java
new file mode 100644
index 0000000..0d193a2
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointPackageGroup.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2000-2012 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.debugger.ui;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.util.PlatformIcons;
+import com.intellij.xdebugger.breakpoints.ui.XBreakpointGroup;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+
+public class XBreakpointPackageGroup extends XBreakpointGroup {
+  private static final String DEFAULT_PACKAGE_NAME = DebuggerBundle.message("default.package.name");
+
+  private String myPackageName;
+
+  public XBreakpointPackageGroup(String packageName) {
+    myPackageName = packageName;
+  }
+
+  @Override
+  public Icon getIcon(boolean isOpen) {
+    return PlatformIcons.PACKAGE_ICON;
+  }
+
+  @NotNull
+  @Override
+  public String getName() {
+    String packageName = getPackageName();
+    return StringUtil.isEmpty(packageName) ? DEFAULT_PACKAGE_NAME : packageName;
+  }
+
+  @NotNull
+  public String getPackageName() {
+    return myPackageName;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AddFieldBreakpointDialog.form b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AddFieldBreakpointDialog.form
new file mode 100644
index 0000000..5db94cf
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AddFieldBreakpointDialog.form
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.debugger.ui.breakpoints.AddFieldBreakpointDialog">
+  <grid id="dbe86" binding="myPanel" row-count="6" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="6">
+    <margin top="0" left="0" bottom="0" right="0"/>
+    <constraints>
+      <xy x="74" y="134" width="245" height="152"/>
+      <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+        <preferred-size width="200" height="-1"/>
+      </grid>
+    </constraints>
+    <properties/>
+    <border type="none"/>
+    <children>
+      <component id="9636d" class="com.intellij.openapi.ui.TextFieldWithBrowseButton" binding="myClassChooser">
+        <constraints>
+          <xy x="0" y="26" width="245" height="22"/>
+          <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+            <preferred-size width="150" height="-1"/>
+          </grid>
+        </constraints>
+        <properties/>
+      </component>
+      <component id="c2ef3" class="com.intellij.openapi.ui.TextFieldWithBrowseButton" binding="myFieldChooser">
+        <constraints>
+          <xy x="0" y="80" width="245" height="22"/>
+          <grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+            <preferred-size width="150" height="-1"/>
+          </grid>
+        </constraints>
+        <properties/>
+      </component>
+      <xy id="3cfba" hgap="-1" vgap="-1">
+        <margin top="0" left="0" bottom="0" right="0"/>
+        <constraints>
+          <xy x="0" y="151" width="245" height="1"/>
+          <grid row="5" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="2" fill="1">
+            <minimum-size width="-1" height="1"/>
+            <maximum-size width="-1" height="1"/>
+          </grid>
+        </constraints>
+        <properties/>
+        <border type="bevel-raised"/>
+        <children/>
+      </xy>
+      <vspacer id="339be">
+        <constraints>
+          <xy x="117" y="108" width="11" height="24"/>
+          <grid row="4" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2"/>
+        </constraints>
+      </vspacer>
+      <component id="e8c64" class="javax.swing.JLabel">
+        <constraints>
+          <xy x="0" y="56" width="69" height="16"/>
+          <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0"/>
+        </constraints>
+        <properties>
+          <text resource-bundle="messages/DebuggerBundle" key="label.add.field.breakpoint.dialog.field.name"/>
+        </properties>
+      </component>
+      <component id="c159b" class="javax.swing.JLabel">
+        <constraints>
+          <xy x="0" y="2" width="181" height="16"/>
+          <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0"/>
+        </constraints>
+        <properties>
+          <text resource-bundle="messages/DebuggerBundle" key="label.add.field.breakpoint.dialog.fq.name"/>
+        </properties>
+      </component>
+    </children>
+  </grid>
+</form>
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AddFieldBreakpointDialog.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AddFieldBreakpointDialog.java
new file mode 100644
index 0000000..f325da1
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AddFieldBreakpointDialog.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * @author: Eugene Zhuravlev
+ * Date: Sep 11, 2002
+ * Time: 5:23:47 PM
+ */
+package com.intellij.debugger.ui.breakpoints;
+
+import com.intellij.codeInsight.generation.PsiFieldMember;
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.ide.util.MemberChooser;
+import com.intellij.ide.util.TreeClassChooser;
+import com.intellij.ide.util.TreeClassChooserFactory;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.openapi.ui.TextFieldWithBrowseButton;
+import com.intellij.psi.*;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.ui.DocumentAdapter;
+import com.intellij.util.Function;
+import com.intellij.util.containers.ContainerUtil;
+
+import javax.swing.*;
+import javax.swing.event.DocumentEvent;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.List;
+
+abstract class AddFieldBreakpointDialog extends DialogWrapper {
+  private final Project myProject;
+  private JPanel myPanel;
+  private TextFieldWithBrowseButton myFieldChooser;
+  private TextFieldWithBrowseButton myClassChooser;
+
+  public AddFieldBreakpointDialog(Project project) {
+    super(project, true);
+    myProject = project;
+    setTitle(DebuggerBundle.message("add.field.breakpoint.dialog.title"));
+    init();
+  }
+
+  protected JComponent createCenterPanel() {
+    myClassChooser.getTextField().getDocument().addDocumentListener(new DocumentAdapter() {
+      public void textChanged(DocumentEvent event) {
+        updateUI();
+      }
+    });
+
+    myClassChooser.addActionListener(new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        PsiClass currentClass = getSelectedClass();
+        TreeClassChooser chooser = TreeClassChooserFactory.getInstance(myProject).createAllProjectScopeChooser(DebuggerBundle.message("add.field.breakpoint.dialog.classchooser.title"));
+        if (currentClass != null) {
+          PsiFile containingFile = currentClass.getContainingFile();
+          if (containingFile != null) {
+            PsiDirectory containingDirectory = containingFile.getContainingDirectory();
+            if (containingDirectory != null) {
+              chooser.selectDirectory(containingDirectory);
+            }
+          }
+        }
+        chooser.showDialog();
+        PsiClass selectedClass = chooser.getSelected();
+        if (selectedClass != null) {
+          myClassChooser.setText(selectedClass.getQualifiedName());
+        }
+      }
+    });
+
+    myFieldChooser.addActionListener(new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        PsiClass selectedClass = getSelectedClass();
+        if (selectedClass != null) {
+          PsiField[] fields = selectedClass.getFields();
+          MemberChooser<PsiFieldMember> chooser = new MemberChooser<PsiFieldMember>(ContainerUtil.map2Array(fields, PsiFieldMember.class, new Function<PsiField, PsiFieldMember>() {
+            public PsiFieldMember fun(final PsiField s) {
+              return new PsiFieldMember(s);
+            }
+          }), false, false, myProject);
+          chooser.setTitle(DebuggerBundle.message("add.field.breakpoint.dialog.field.chooser.title", fields.length));
+          chooser.setCopyJavadocVisible(false);
+          chooser.show();
+          List<PsiFieldMember> selectedElements = chooser.getSelectedElements();
+          if (selectedElements != null && selectedElements.size() == 1) {
+            PsiField field = selectedElements.get(0).getElement();
+            myFieldChooser.setText(field.getName());
+          }
+        }
+      }
+    });
+    myFieldChooser.setEnabled(false);
+    return myPanel;
+  }
+
+  private void updateUI() {
+    PsiClass selectedClass = getSelectedClass();
+    myFieldChooser.setEnabled(selectedClass != null);
+  }
+
+  private PsiClass getSelectedClass() {
+    final PsiManager psiManager = PsiManager.getInstance(myProject);
+    String classQName = myClassChooser.getText();
+    if ("".equals(classQName)) {
+      return null;
+    }
+    return JavaPsiFacade.getInstance(psiManager.getProject()).findClass(classQName, GlobalSearchScope.allScope(myProject));
+  }
+
+  public JComponent getPreferredFocusedComponent() {
+    return myClassChooser.getTextField();
+  }
+
+  public String getClassName() {
+    return myClassChooser.getText();
+  }
+
+  protected String getDimensionServiceKey(){
+    return "#com.intellij.debugger.ui.breakpoints.BreakpointsConfigurationDialogFactory.BreakpointsConfigurationDialog.AddFieldBreakpointDialog";
+  }
+
+  public String getFieldName() {
+    return myFieldChooser.getText();
+  }
+
+  protected abstract boolean validateData();
+
+  protected void doOKAction() {
+    if(validateData()) {
+      super.doOKAction();
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AddWildcardBreakpointDialog.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AddWildcardBreakpointDialog.java
new file mode 100644
index 0000000..c18acb7
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AddWildcardBreakpointDialog.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2004-2006 Alexey Efimov
+ *
+ * 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.debugger.ui.breakpoints;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.openapi.ui.Messages;
+
+import javax.swing.*;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: Jan 10, 2006
+ */
+public class AddWildcardBreakpointDialog extends DialogWrapper {
+  private JPanel myPanel;
+  private JTextField myClassPatternField;
+  private JTextField myMethodNameField;
+
+  protected AddWildcardBreakpointDialog(Project project) {
+    super(project, true);
+    setTitle("Add Method Breakpoint");
+    init();
+  }
+
+  protected void doOKAction() {
+    if (getClassPattern().length() == 0) {
+      Messages.showErrorDialog(myPanel, "Class pattern not specified");
+      return;
+    }
+    if (getMethodName().length() == 0) {
+      Messages.showErrorDialog(myPanel, "Method name not specified");
+      return;
+    }
+    super.doOKAction();
+  }
+
+  public JComponent getPreferredFocusedComponent() {
+    return myClassPatternField;
+  }
+
+  public String getClassPattern() {
+    return myClassPatternField.getText().trim();
+  }
+
+  public String getMethodName() {
+    return myMethodNameField.getText().trim();
+  }
+
+  protected JComponent createCenterPanel() {
+    return myPanel;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AddWildcardBreakpointForm.form b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AddWildcardBreakpointForm.form
new file mode 100644
index 0000000..4866c1e
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AddWildcardBreakpointForm.form
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.debugger.ui.breakpoints.AddWildcardBreakpointDialog">
+  <grid id="9b829" binding="myPanel" row-count="5" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+    <margin top="0" left="0" bottom="0" right="0"/>
+    <constraints>
+      <xy x="120" y="73" width="414" height="149"/>
+      <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0"/>
+    </constraints>
+    <properties/>
+    <border type="none"/>
+    <children>
+      <component id="ee438" class="javax.swing.JTextField" binding="myClassPatternField">
+        <constraints>
+          <xy x="2" y="27" width="410" height="22"/>
+          <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0">
+            <preferred-size width="300" height="-1"/>
+          </grid>
+        </constraints>
+        <properties/>
+      </component>
+      <component id="4c818" class="javax.swing.JLabel">
+        <constraints>
+          <xy x="2" y="56" width="84" height="16"/>
+          <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0"/>
+        </constraints>
+        <properties>
+          <labelFor value="2d944"/>
+          <nextFocusableComponent value=""/>
+          <text value="&amp;Method name:"/>
+        </properties>
+      </component>
+      <component id="2d944" class="javax.swing.JTextField" binding="myMethodNameField">
+        <constraints>
+          <xy x="2" y="79" width="410" height="22"/>
+          <grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0">
+            <preferred-size width="150" height="-1"/>
+          </grid>
+        </constraints>
+        <properties/>
+      </component>
+      <vspacer id="2b528">
+        <constraints>
+          <xy x="201" y="101" width="11" height="46"/>
+          <grid row="4" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0"/>
+        </constraints>
+      </vspacer>
+      <component id="7fca9" class="javax.swing.JLabel">
+        <constraints>
+          <xy x="2" y="4" width="82" height="16"/>
+          <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0"/>
+        </constraints>
+        <properties>
+          <labelFor value="ee438"/>
+          <text value="&amp;Class pattern:"/>
+        </properties>
+      </component>
+    </children>
+  </grid>
+</form>
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AnyExceptionBreakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AnyExceptionBreakpoint.java
new file mode 100644
index 0000000..3d1ff85
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AnyExceptionBreakpoint.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class AnyExceptionBreakpoint
+ * @author Jeka
+ */
+package com.intellij.debugger.ui.breakpoints;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.DebugProcess;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.Key;
+import com.sun.jdi.ReferenceType;
+import org.jdom.Element;
+import org.jetbrains.annotations.NonNls;
+
+public class AnyExceptionBreakpoint extends ExceptionBreakpoint {
+  public static final @NonNls Key<AnyExceptionBreakpoint> ANY_EXCEPTION_BREAKPOINT = BreakpointCategory.lookup("breakpoint_any");
+
+  protected AnyExceptionBreakpoint(Project project) {
+    super(project, null, null);
+    ENABLED = false;
+  }
+
+  public Key<AnyExceptionBreakpoint> getCategory() {
+    return ANY_EXCEPTION_BREAKPOINT;
+  }
+
+  public String getDisplayName() {
+    return DebuggerBundle.message("breakpoint.any.exception.display.name");
+  }
+
+  public void createRequest(DebugProcessImpl debugProcess) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    if (!ENABLED || !debugProcess.isAttached() || debugProcess.areBreakpointsMuted() || !debugProcess.getRequestsManager().findRequests(this).isEmpty()) {
+      return;
+    }
+    super.processClassPrepare(debugProcess, null);
+  }
+
+  public void processClassPrepare(DebugProcess debugProcess, ReferenceType refType) {
+    // should be emty - does not make sense for this breakpoint
+  }
+
+  public void readExternal(Element parentNode) throws InvalidDataException {
+    try {
+      super.readExternal(parentNode);
+    }
+    catch (InvalidDataException e) {
+      if(!READ_NO_CLASS_NAME.equals(e.getMessage())) throw e;
+    }
+  }
+
+}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AnyExceptionBreakpointFactory.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AnyExceptionBreakpointFactory.java
new file mode 100644
index 0000000..79398de
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AnyExceptionBreakpointFactory.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.breakpoints;
+
+import com.intellij.debugger.ui.breakpoints.actions.BreakpointPanelAction;
+import com.intellij.icons.AllIcons;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.openapi.util.Key;
+import org.jdom.Element;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: Apr 26, 2005
+ */
+public class AnyExceptionBreakpointFactory extends BreakpointFactory{
+  public Breakpoint createBreakpoint(Project project, final Element element) {
+    return new AnyExceptionBreakpoint(project);
+  }
+
+  public Icon getIcon() {
+    return AllIcons.Debugger.Db_exception_breakpoint;
+  }
+
+  public Icon getDisabledIcon() {
+    return AllIcons.Debugger.Db_disabled_exception_breakpoint;
+  }
+
+  @Override
+  protected String getHelpID() {
+    return null;  //To change body of implemented methods use File | Settings | File Templates.
+  }
+
+  @Override
+  public String getDisplayName() {
+    return null;  //To change body of implemented methods use File | Settings | File Templates.
+  }
+
+  @Override
+  public BreakpointPropertiesPanel createBreakpointPropertiesPanel(Project project, boolean compact) {
+    return new ExceptionBreakpointPropertiesPanel(project, compact);
+  }
+
+  @Override
+  protected BreakpointPanelAction[] createBreakpointPanelActions(Project project, DialogWrapper parentDialog) {
+    return new BreakpointPanelAction[0];  //To change body of implemented methods use File | Settings | File Templates.
+  }
+
+  @Override
+  public boolean breakpointCanBeRemoved(Breakpoint breakpoint) {
+    return false;
+  }
+
+  public @Nullable BreakpointPanel createBreakpointPanel(Project project, DialogWrapper parentDialog) {
+    return null;
+  }
+
+  public Key<AnyExceptionBreakpoint> getBreakpointCategory() {
+    return AnyExceptionBreakpoint.ANY_EXCEPTION_BREAKPOINT;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java
new file mode 100644
index 0000000..b738089
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class Breakpoint
+ * @author Jeka
+ */
+package com.intellij.debugger.ui.breakpoints;
+
+import com.intellij.debugger.*;
+import com.intellij.debugger.engine.*;
+import com.intellij.debugger.engine.evaluation.*;
+import com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilderImpl;
+import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator;
+import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
+import com.intellij.debugger.engine.requests.RequestManagerImpl;
+import com.intellij.debugger.jdi.StackFrameProxyImpl;
+import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
+import com.intellij.debugger.requests.ClassPrepareRequestor;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.*;
+import com.intellij.psi.PsiClass;
+import com.intellij.util.StringBuilderSpinAllocator;
+import com.sun.jdi.ObjectReference;
+import com.sun.jdi.ReferenceType;
+import com.sun.jdi.Value;
+import com.sun.jdi.VoidValue;
+import com.sun.jdi.event.LocatableEvent;
+import org.jdom.Element;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.util.List;
+
+public abstract class Breakpoint extends FilteredRequestor implements ClassPrepareRequestor {
+  public boolean ENABLED = true;
+  public boolean LOG_ENABLED = false;
+  public boolean LOG_EXPRESSION_ENABLED = false;
+  private TextWithImports  myLogMessage; // an expression to be evaluated and printed
+  @NonNls private static final String LOG_MESSAGE_OPTION_NAME = "LOG_MESSAGE";
+  public static final Breakpoint[] EMPTY_ARRAY = new Breakpoint[0];
+  protected boolean myCachedVerifiedState = false;
+
+  protected Breakpoint(@NotNull Project project) {
+    super(project);
+    myLogMessage = new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, "");
+    //noinspection AbstractMethodCallInConstructor
+    final BreakpointDefaults defaults = DebuggerManagerEx.getInstanceEx(project).getBreakpointManager().getBreakpointDefaults(getCategory());
+    SUSPEND_POLICY = defaults.getSuspendPolicy();
+    CONDITION_ENABLED = defaults.isConditionEnabled();
+  }
+
+  public abstract PsiClass getPsiClass();
+  /**
+   * Request for creating all needed JPDA requests in the specified VM
+   * @param debuggerProcess the requesting process
+   */
+  public abstract void createRequest(DebugProcessImpl debuggerProcess);
+
+  /**
+   * Request for creating all needed JPDA requests in the specified VM
+   * @param debuggerProcess the requesting process
+   */
+  public abstract void processClassPrepare(DebugProcess debuggerProcess, final ReferenceType referenceType);
+
+  public abstract String getDisplayName ();
+  
+  public String getShortName() {
+    return getDisplayName();
+  }
+
+  @Nullable
+  public String getClassName() {
+    return null;
+  }
+
+  public void markVerified(boolean isVerified) {
+    myCachedVerifiedState = isVerified;
+  }
+
+  @Nullable
+  public String getShortClassName() {
+    final String className = getClassName();
+    if (className != null) {
+      final int dotIndex = className.lastIndexOf('.');
+      return dotIndex >= 0 && dotIndex + 1 < className.length()? className.substring(dotIndex + 1) : className;
+    }
+    return className;
+  }
+
+  @Nullable
+  public String getPackageName() {
+    return null;
+  }
+
+  public abstract Icon getIcon();
+
+  public abstract void reload();
+
+  /**
+   * returns UI representation
+   */
+  public abstract String getEventMessage(LocatableEvent event);
+
+  public abstract boolean isValid();
+
+  public abstract Key<? extends Breakpoint> getCategory();
+
+  /**
+   * Associates breakpoint with class.
+   *    Create requests for loaded class and registers callback for loading classes
+   * @param debugProcess the requesting process
+   */
+  protected void createOrWaitPrepare(DebugProcessImpl debugProcess, String classToBeLoaded) {
+    debugProcess.getRequestsManager().callbackOnPrepareClasses(this, classToBeLoaded);
+
+    List list = debugProcess.getVirtualMachineProxy().classesByName(classToBeLoaded);
+    for (final Object aList : list) {
+      ReferenceType refType = (ReferenceType)aList;
+      if (refType.isPrepared()) {
+        processClassPrepare(debugProcess, refType);
+      }
+    }
+  }
+
+  protected void createOrWaitPrepare(final DebugProcessImpl debugProcess, final SourcePosition classPosition) {
+    debugProcess.getRequestsManager().callbackOnPrepareClasses(this, classPosition);
+
+    List list = debugProcess.getPositionManager().getAllClasses(classPosition);
+    for (final Object aList : list) {
+      ReferenceType refType = (ReferenceType)aList;
+      if (refType.isPrepared()) {
+        processClassPrepare(debugProcess, refType);
+      }
+    }
+  }
+
+  protected ObjectReference getThisObject(SuspendContextImpl context, LocatableEvent event) throws EvaluateException {
+    ThreadReferenceProxyImpl thread = context.getThread();
+    if(thread != null) {
+      StackFrameProxyImpl stackFrameProxy = thread.frame(0);
+      if(stackFrameProxy != null) {
+        return stackFrameProxy.thisObject();
+      }
+    }
+    return null;
+  }
+
+  public boolean processLocatableEvent(final SuspendContextCommandImpl action, final LocatableEvent event) throws EventProcessingException {
+    final SuspendContextImpl context = action.getSuspendContext();
+    if(!isValid()) {
+      context.getDebugProcess().getRequestsManager().deleteRequest(this);
+      return false;
+    }
+
+    final String[] title = {DebuggerBundle.message("title.error.evaluating.breakpoint.condition") };
+
+    try {
+      final StackFrameProxyImpl frameProxy = context.getThread().frame(0);
+      if (frameProxy == null) {
+        // might be if the thread has been collected
+        return false;
+      }
+
+      final EvaluationContextImpl evaluationContext = new EvaluationContextImpl(
+        action.getSuspendContext(),
+        frameProxy,
+        getThisObject(context, event)
+      );
+
+      if(!evaluateCondition(evaluationContext, event)) {
+        return false;
+      }
+
+      title[0] = DebuggerBundle.message("title.error.evaluating.breakpoint.action");
+      runAction(evaluationContext, event);
+    }
+    catch (final EvaluateException ex) {
+      if(ApplicationManager.getApplication().isUnitTestMode()) {
+        System.out.println(ex.getMessage());
+        return false;
+      }
+
+      throw new EventProcessingException(title[0], ex.getMessage(), ex);
+    } 
+
+    return true;
+  }
+
+  private void runAction(final EvaluationContextImpl context, LocatableEvent event) {
+    if (LOG_ENABLED || LOG_EXPRESSION_ENABLED) {
+      final StringBuilder buf = StringBuilderSpinAllocator.alloc();
+      try {
+        if (LOG_ENABLED) {
+          buf.append(getEventMessage(event));
+          buf.append("\n");
+        }
+        final DebugProcessImpl debugProcess = context.getDebugProcess();
+        final TextWithImports expressionToEvaluate = getLogMessage();
+        if (LOG_EXPRESSION_ENABLED && expressionToEvaluate != null && !"".equals(expressionToEvaluate.getText())) {
+          if(!debugProcess.isAttached()) {
+            return;
+          }
+  
+          try {
+            ExpressionEvaluator evaluator = DebuggerInvocationUtil.commitAndRunReadAction(getProject(), new EvaluatingComputable<ExpressionEvaluator>() {
+              public ExpressionEvaluator compute() throws EvaluateException {
+                return EvaluatorBuilderImpl.build(expressionToEvaluate, ContextUtil.getContextElement(context), ContextUtil.getSourcePosition(context));
+              }
+            });
+            final Value eval = evaluator.evaluate(context);
+            final String result = eval instanceof VoidValue ? "void" : DebuggerUtils.getValueAsString(context, eval);
+            buf.append(result);
+          }
+          catch (EvaluateException e) {
+            buf.append(DebuggerBundle.message("error.unable.to.evaluate.expression"));
+            buf.append(" \"");
+            buf.append(expressionToEvaluate);
+            buf.append("\"");
+            buf.append(" : ");
+            buf.append(e.getMessage());
+          }
+          buf.append("\n");
+        }
+        if (buf.length() > 0) {
+          debugProcess.printToConsole(buf.toString());
+        }
+      }
+      finally {
+        StringBuilderSpinAllocator.dispose(buf);
+      }
+    }
+  }
+
+  public final void updateUI() {
+    updateUI(EmptyRunnable.getInstance());
+  }
+
+  public void updateUI(@NotNull Runnable afterUpdate) {
+  }
+
+  public void delete() {
+    RequestManagerImpl.deleteRequests(this);
+  }
+
+  public void readExternal(Element parentNode) throws InvalidDataException {
+    super.readExternal(parentNode);
+    String logMessage = JDOMExternalizerUtil.readField(parentNode, LOG_MESSAGE_OPTION_NAME);
+    if (logMessage != null) {
+      setLogMessage(new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, logMessage));
+    }
+  }
+
+  public void writeExternal(Element parentNode) throws WriteExternalException {
+    super.writeExternal(parentNode);
+    JDOMExternalizerUtil.writeField(parentNode, LOG_MESSAGE_OPTION_NAME, getLogMessage().toExternalForm());
+  }
+
+  public TextWithImports getLogMessage() {
+    return myLogMessage;
+  }
+
+  public void setLogMessage(TextWithImports logMessage) {
+    myLogMessage = logMessage;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointCategory.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointCategory.java
new file mode 100644
index 0000000..ec7fbe0
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointCategory.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.breakpoints;
+
+import com.intellij.openapi.util.Key;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: Jan 18, 2007
+ */
+public final class BreakpointCategory {
+  private static final Map<String, Key> ourMap = new HashMap<String, Key>();
+
+  private BreakpointCategory() {
+  }
+
+  @NotNull
+  public static <T extends Breakpoint> Key<T> lookup(String name) {
+    Key<T> key = ourMap.get(name);
+    if (key == null) {
+      key = Key.create(name);
+      ourMap.put(name, key);
+    }
+    return key;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointDefaults.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointDefaults.java
new file mode 100644
index 0000000..89b5f9c
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointDefaults.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2000-2012 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.debugger.ui.breakpoints;
+
+import com.intellij.debugger.settings.DebuggerSettings;
+import org.jetbrains.annotations.NotNull;
+
+/**
+* @author Eugene Zhuravlev
+*         Date: 8/30/12
+*/
+public final class BreakpointDefaults {
+  private String mySuspendPolicy = DebuggerSettings.SUSPEND_ALL;
+  private boolean myIsConditionEnabled = true;
+
+  public BreakpointDefaults() {
+  }
+
+  public BreakpointDefaults(String suspendPolicy, boolean conditionEnabled) {
+    setSuspendPolicy(suspendPolicy);
+    this.myIsConditionEnabled = conditionEnabled;
+  }
+
+  @NotNull
+  public String getSuspendPolicy() {
+    return mySuspendPolicy;
+  }
+
+  public void setSuspendPolicy(String suspendPolicy) {
+    if (DebuggerSettings.SUSPEND_THREAD.equals(suspendPolicy) || DebuggerSettings.SUSPEND_ALL.equals( suspendPolicy)) {
+      mySuspendPolicy = suspendPolicy;
+    }
+  }
+
+  public boolean isConditionEnabled() {
+    return myIsConditionEnabled;
+  }
+
+  public void setConditionEnabled(boolean isConditionEnabled) {
+    myIsConditionEnabled = isConditionEnabled;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointFactory.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointFactory.java
new file mode 100644
index 0000000..6389fdd
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointFactory.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.breakpoints;
+
+import com.intellij.debugger.ui.breakpoints.actions.BreakpointPanelAction;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.openapi.util.Key;
+import com.intellij.xdebugger.impl.breakpoints.ui.BreakpointItem;
+import org.jdom.Element;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+
+/**
+ * Used to deexternalize breakpoints of certain category while reading saved configuration and for creating configuration UI
+ */
+public abstract class BreakpointFactory {
+  public static final ExtensionPointName<BreakpointFactory> EXTENSION_POINT_NAME =
+    ExtensionPointName.create("com.intellij.debugger.breakpointFactory");
+
+  public static BreakpointFactory[] getBreakpointFactories() {
+    return ApplicationManager.getApplication().getExtensions(EXTENSION_POINT_NAME);
+  }
+
+  public abstract Breakpoint createBreakpoint(Project project, final Element element);
+
+  public abstract Key<? extends Breakpoint> getBreakpointCategory();
+
+  public BreakpointPanel createBreakpointPanel(final Project project, final DialogWrapper parentDialog) {
+    BreakpointPanel panel =
+      new BreakpointPanel(project, createBreakpointPropertiesPanel(project, false), createBreakpointPanelActions(project, parentDialog),
+                          getBreakpointCategory(), getDisplayName(), getHelpID());
+    configureBreakpointPanel(panel);
+    return panel;
+  }
+
+  public abstract Icon getIcon();
+
+  public abstract Icon getDisabledIcon();
+
+  @Nullable
+  public static BreakpointFactory getInstance(Key<? extends Breakpoint> category) {
+    final BreakpointFactory[] allFactories = getBreakpointFactories();
+    for (final BreakpointFactory factory : allFactories) {
+      if (category.equals(factory.getBreakpointCategory())) {
+        return factory;
+      }
+    }
+    return null;
+  }
+
+  protected void configureBreakpointPanel(BreakpointPanel panel) {
+  }
+
+  protected abstract String getHelpID();
+
+  public abstract String getDisplayName();
+
+  @Nullable
+  public abstract BreakpointPropertiesPanel createBreakpointPropertiesPanel(Project project, boolean compact);
+
+  protected abstract BreakpointPanelAction[] createBreakpointPanelActions(Project project, DialogWrapper parentDialog);
+
+  @Nullable
+  public Breakpoint addBreakpoint(Project project) {
+    return null;
+  }
+
+  public boolean canAddBreakpoints() {
+    return false;
+  }
+
+  public boolean breakpointCanBeRemoved(Breakpoint breakpoint) {
+    return true;
+  }
+
+  public BreakpointItem createBreakpointItem(final Breakpoint breakpoint) {
+    return new JavaBreakpointItem(this, breakpoint);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointManager.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointManager.java
new file mode 100644
index 0000000..8c77bc1
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointManager.java
@@ -0,0 +1,1100 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class BreakpointManager
+ * @author Jeka
+ */
+package com.intellij.debugger.ui.breakpoints;
+
+import com.intellij.codeInsight.folding.impl.actions.ExpandRegionAction;
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerInvocationUtil;
+import com.intellij.debugger.SourcePosition;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.DebuggerUtils;
+import com.intellij.debugger.engine.evaluation.CodeFragmentKind;
+import com.intellij.debugger.engine.evaluation.TextWithImportsImpl;
+import com.intellij.debugger.engine.requests.RequestManagerImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerContextListener;
+import com.intellij.debugger.impl.DebuggerManagerImpl;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.debugger.ui.JavaDebuggerSupport;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.ModalityState;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.EditorFactory;
+import com.intellij.openapi.editor.event.*;
+import com.intellij.openapi.editor.markup.GutterIconRenderer;
+import com.intellij.openapi.editor.markup.MarkupEditorFilterFactory;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.fileEditor.FileEditor;
+import com.intellij.openapi.fileEditor.FileEditorManager;
+import com.intellij.openapi.fileEditor.TextEditor;
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.fileTypes.StdFileTypes;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.startup.StartupManager;
+import com.intellij.openapi.ui.MessageType;
+import com.intellij.openapi.util.*;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiField;
+import com.intellij.psi.PsiFile;
+import com.intellij.util.Alarm;
+import com.intellij.util.EventDispatcher;
+import com.intellij.util.IJSwingUtilities;
+import com.intellij.util.containers.HashMap;
+import com.intellij.xdebugger.XDebuggerUtil;
+import com.intellij.xdebugger.impl.DebuggerSupport;
+import com.intellij.xdebugger.impl.XDebugSessionImpl;
+import com.sun.jdi.Field;
+import com.sun.jdi.InternalException;
+import com.sun.jdi.ObjectReference;
+import com.sun.jdi.ThreadReference;
+import com.sun.jdi.request.*;
+import gnu.trove.TIntHashSet;
+import org.jdom.Element;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.awt.event.MouseEvent;
+import java.util.*;
+
+public class BreakpointManager implements JDOMExternalizable {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.breakpoints.BreakpointManager");
+
+  @NonNls private static final String RULES_GROUP_NAME = "breakpoint_rules";
+  private final Project myProject;
+  private AnyExceptionBreakpoint myAnyExceptionBreakpoint;
+  private final List<Breakpoint> myBreakpoints = new ArrayList<Breakpoint>(); // breakpoints storage, access should be synchronized
+  private final List<EnableBreakpointRule> myBreakpointRules = new ArrayList<EnableBreakpointRule>(); // breakpoint rules
+  @Nullable private List<Breakpoint> myBreakpointsListForIteration = null; // another list for breakpoints iteration, unsynchronized access ok
+  private final Map<Document, List<BreakpointWithHighlighter>> myDocumentBreakpoints = new HashMap<Document, List<BreakpointWithHighlighter>>();
+  private final Map<String, String> myUIProperties = new java.util.HashMap<String, String>();
+  private final Map<Key<? extends Breakpoint>, BreakpointDefaults> myBreakpointDefaults = new HashMap<Key<? extends Breakpoint>, BreakpointDefaults>();
+
+  private final EventDispatcher<BreakpointManagerListener> myDispatcher = EventDispatcher.create(BreakpointManagerListener.class);
+
+  private final StartupManager myStartupManager;
+
+  @NonNls private static final String MASTER_BREAKPOINT_TAGNAME = "master_breakpoint";
+  @NonNls private static final String SLAVE_BREAKPOINT_TAGNAME = "slave_breakpoint";
+  @NonNls private static final String DEFAULT_SUSPEND_POLICY_ATTRIBUTE_NAME = "default_suspend_policy";
+  @NonNls private static final String DEFAULT_CONDITION_STATE_ATTRIBUTE_NAME = "default_condition_enabled";
+
+  private void update(@NotNull List<BreakpointWithHighlighter> breakpoints) {
+    final TIntHashSet intHash = new TIntHashSet();
+
+    for (BreakpointWithHighlighter breakpoint : breakpoints) {
+      SourcePosition sourcePosition = breakpoint.getSourcePosition();
+      breakpoint.reload();
+
+      if (breakpoint.isValid()) {
+        if (breakpoint.getSourcePosition().getLine() != sourcePosition.getLine()) {
+          fireBreakpointChanged(breakpoint);
+        }
+
+        if (intHash.contains(breakpoint.getLineIndex())) {
+          remove(breakpoint);
+        }
+        else {
+          intHash.add(breakpoint.getLineIndex());
+        }
+      }
+      else {
+        remove(breakpoint);
+      }
+    }
+  }
+
+  /*
+  // todo: not needed??
+  private void setInvalid(final BreakpointWithHighlighter breakpoint) {
+    Collection<DebuggerSession> sessions = DebuggerManagerEx.getInstanceEx(myProject).getSessions();
+
+    for (Iterator<DebuggerSession> iterator = sessions.getSectionsIterator(); getSectionsIterator.hasNext();) {
+      DebuggerSession session = iterator.next();
+      final DebugProcessImpl process = session.getProcess();
+      process.getManagerThread().schedule(new DebuggerCommandImpl() {
+        protected void action() throws Exception {
+          process.getRequestsManager().deleteRequest(breakpoint);
+          process.getRequestsManager().setInvalid(breakpoint, "Source code changed");
+          breakpoint.updateUI();
+        }
+      });
+    }
+  }
+  */
+
+  private void remove(final BreakpointWithHighlighter breakpoint) {
+    DebuggerInvocationUtil.invokeLater(myProject, new Runnable() {
+      @Override
+      public void run() {
+        removeBreakpoint(breakpoint);
+      }
+    });
+  }
+
+  public BreakpointManager(@NotNull Project project, @NotNull StartupManager startupManager, @NotNull DebuggerManagerImpl debuggerManager) {
+    myProject = project;
+    myStartupManager = startupManager;
+    debuggerManager.getContextManager().addListener(new DebuggerContextListener() {
+      private DebuggerSession myPreviousSession;
+
+      @Override
+      public void changeEvent(@NotNull DebuggerContextImpl newContext, int event) {
+        if (newContext.getDebuggerSession() != myPreviousSession || event == DebuggerSession.EVENT_DETACHED) {
+          updateBreakpointsUI();
+          myPreviousSession = newContext.getDebuggerSession();
+        }
+      }
+    });
+  }
+
+  public void init() {
+    EditorEventMulticaster eventMulticaster = EditorFactory.getInstance().getEventMulticaster();
+    EditorMouseAdapter myEditorMouseListener = new EditorMouseAdapter() {
+      @Nullable private EditorMouseEvent myMousePressedEvent;
+
+      @Nullable
+      private Breakpoint toggleBreakpoint(final boolean mostSuitingBreakpoint, final int line) {
+        final Editor editor = FileEditorManager.getInstance(myProject).getSelectedTextEditor();
+        if (editor == null) {
+          return null;
+        }
+        final Document document = editor.getDocument();
+        final PsiFile psiFile = PsiDocumentManager.getInstance(myProject).getPsiFile(document);
+        if (psiFile == null) {
+          return null;
+        }
+        final FileType fileType = psiFile.getFileType();
+        boolean isInsideCompiledClass = StdFileTypes.CLASS.equals(fileType);
+        if (!isInsideCompiledClass && !(DebuggerUtils.supportsJVMDebugging(fileType) || DebuggerUtils.supportsJVMDebugging(psiFile))) {
+          return null;
+        }
+        PsiDocumentManager.getInstance(myProject).commitDocument(document);
+
+        int offset = editor.getCaretModel().getOffset();
+        int editorLine = editor.getDocument().getLineNumber(offset);
+        if (editorLine != line) {
+          if (line < 0 || line >= document.getLineCount()) {
+            return null;
+          }
+          offset = editor.getDocument().getLineStartOffset(line);
+        }
+
+        ExpandRegionAction.expandRegionAtCaret(myProject, editor);
+
+        Breakpoint breakpoint = findBreakpoint(document, offset, null);
+        if (breakpoint == null) {
+          if (mostSuitingBreakpoint || isInsideCompiledClass) {
+            breakpoint = addFieldBreakpoint(document, offset);
+            if (breakpoint == null) {
+              breakpoint = addMethodBreakpoint(document, line);
+            }
+            if (breakpoint == null && !isInsideCompiledClass) {
+              breakpoint = addLineBreakpoint(document, line);
+            }
+          }
+          else {
+            breakpoint = addLineBreakpoint(document, line);
+
+            if (breakpoint == null) {
+              breakpoint = addMethodBreakpoint(document, line);
+            }
+          }
+
+          if (breakpoint != null) {
+            RequestManagerImpl.createRequests(breakpoint);
+          }
+          return breakpoint;
+        }
+        else {
+          removeBreakpoint(breakpoint);
+          return null;
+        }
+      }
+
+      private boolean isFromMyProject(Editor editor) {
+        FileEditor[] allEditors = FileEditorManager.getInstance(myProject).getAllEditors();
+        for (FileEditor ed : allEditors) {
+          if (!(ed instanceof TextEditor)) {
+            continue;
+          }
+          if (((TextEditor)ed).getEditor().equals(editor)) {
+            return true;
+          }
+        }
+        return false;
+      }
+
+      //mousePressed + mouseReleased is a hack to keep selection in editor when shift is pressed
+      @Override
+      public void mousePressed(@NotNull EditorMouseEvent e) {
+        if (MarkupEditorFilterFactory.createIsDiffFilter().avaliableIn(e.getEditor())) return;
+
+        if (e.isConsumed()) return;
+
+        if (e.getArea() == EditorMouseEventArea.LINE_MARKERS_AREA && e.getMouseEvent().isShiftDown()) {
+          myMousePressedEvent = e;
+          e.consume();
+        }
+      }
+
+      @Override
+      public void mouseReleased(@NotNull EditorMouseEvent e) {
+        if (myMousePressedEvent != null) {
+          mouseClicked(e);
+        }
+        myMousePressedEvent = null;
+      }
+
+      @Override
+      public void mouseClicked(@NotNull final EditorMouseEvent e) {
+        if (MarkupEditorFilterFactory.createIsDiffFilter().avaliableIn(e.getEditor())) return;
+
+        if (e.isConsumed()) return;
+
+        if (e.getArea() == EditorMouseEventArea.LINE_MARKERS_AREA) {
+          PsiDocumentManager.getInstance(myProject).commitAndRunReadAction(new Runnable() {
+            @Override
+            public void run() {
+              final Editor editor = e.getEditor();
+              if (!isFromMyProject(editor)) {
+                return;
+              }
+              final int line = editor.xyToLogicalPosition(e.getMouseEvent().getPoint()).line;
+              final Document document = editor.getDocument();
+              if (line < 0 || line >= document.getLineCount()) {
+                return;
+              }
+              MouseEvent event = e.getMouseEvent();
+              if (event.isPopupTrigger()) {
+                return;
+              }
+              if (event.getButton() != 1) {
+                return;
+              }
+              if (e.getMouseEvent().isControlDown() || e.getMouseEvent().isMetaDown()) {
+                return;
+              }
+
+              if (XDebuggerUtil.getInstance().canPutBreakpointAt(myProject, FileDocumentManager.getInstance().getFile(document), line)) {
+                return;
+              }
+              e.consume();
+
+              DebuggerInvocationUtil.invokeLater(myProject, new Runnable() {
+                @Override
+                public void run() {
+                  final Breakpoint breakpoint = toggleBreakpoint(e.getMouseEvent().isAltDown(), line);
+
+
+                  if (e.getMouseEvent().isShiftDown() && breakpoint != null) {
+                    breakpoint.LOG_EXPRESSION_ENABLED = true;
+                    String selection = editor.getSelectionModel().getSelectedText();
+                    String text = selection != null ? selection : DebuggerBundle.message("breakpoint.log.message",
+                                                                                               breakpoint.getDisplayName());
+                    breakpoint.setLogMessage(new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, text));
+                    breakpoint.SUSPEND = false;
+                    editBreakpoint(breakpoint, editor);
+
+
+                    //DialogWrapper dialog = DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager()
+                    //  .createConfigurationDialog(breakpoint, BreakpointPropertiesPanel.CONTROL_LOG_MESSAGE);
+                    //dialog.show();
+                    //
+                    //if (!dialog.isOK()) {
+                    //  removeBreakpoint(breakpoint);
+                    //}
+                  }
+                }
+              });
+            }
+          });
+        }
+      }
+    };
+
+    eventMulticaster.addEditorMouseListener(myEditorMouseListener, myProject);
+
+    final DocumentListener myDocumentListener = new DocumentAdapter() {
+      private final Alarm myUpdateAlarm = new Alarm();
+
+      @Override
+      public void documentChanged(@NotNull final DocumentEvent e) {
+        final Document document = e.getDocument();
+        synchronized (BreakpointManager.this) {
+          List<BreakpointWithHighlighter> breakpoints = myDocumentBreakpoints.get(document);
+
+          if(breakpoints != null) {
+            myUpdateAlarm.cancelAllRequests();
+            // must create new array in order to avoid "concurrent modification" errors
+            final List<BreakpointWithHighlighter> breakpointsToUpdate = new ArrayList<BreakpointWithHighlighter>(breakpoints);
+            myUpdateAlarm.addRequest(new Runnable() {
+              @Override
+              public void run() {
+                if (!myProject.isDisposed()) {
+                  PsiDocumentManager.getInstance(myProject).commitDocument(document);
+                  update(breakpointsToUpdate);
+                }
+              }
+            }, 300, ModalityState.NON_MODAL);
+          }
+        }
+      }
+    };
+
+    eventMulticaster.addDocumentListener(myDocumentListener, myProject);
+  }
+
+  public void editBreakpoint(final Breakpoint breakpoint, final Editor editor) {
+    DebuggerInvocationUtil.swingInvokeLater(myProject, new Runnable() {
+      @Override
+      public void run() {
+        final GutterIconRenderer renderer = ((BreakpointWithHighlighter)breakpoint).getHighlighter().getGutterIconRenderer();
+        if (renderer != null) {
+          DebuggerSupport.getDebuggerSupport(JavaDebuggerSupport.class).getEditBreakpointAction()
+            .editBreakpoint(myProject, editor, breakpoint, renderer);
+        }
+      }
+    });
+  }
+
+  @NotNull
+  public BreakpointDefaults getBreakpointDefaults(Key<? extends Breakpoint> category) {
+    BreakpointDefaults defaults = myBreakpointDefaults.get(category);
+    if (defaults == null) {
+      defaults = new BreakpointDefaults();
+    }
+    return defaults;
+  }
+
+  public void setBreakpointDefaults(Key<? extends Breakpoint> category, BreakpointDefaults defaults) {
+    myBreakpointDefaults.put(category, defaults);
+  }
+
+
+  @Nullable
+  public RunToCursorBreakpoint addRunToCursorBreakpoint(Document document, int lineIndex, final boolean ignoreBreakpoints) {
+    return RunToCursorBreakpoint.create(myProject, document, lineIndex, ignoreBreakpoints);
+  }
+
+  @Nullable
+  public LineBreakpoint addLineBreakpoint(Document document, int lineIndex) {
+    ApplicationManager.getApplication().assertIsDispatchThread();
+    if (!LineBreakpoint.canAddLineBreakpoint(myProject, document, lineIndex)) {
+      return null;
+    }
+
+    LineBreakpoint breakpoint = LineBreakpoint.create(myProject, document, lineIndex);
+    if (breakpoint == null) {
+      return null;
+    }
+
+    addBreakpoint(breakpoint);
+    return breakpoint;
+  }
+
+  @Nullable
+  public FieldBreakpoint addFieldBreakpoint(Field field, ObjectReference object) {
+    ApplicationManager.getApplication().assertIsDispatchThread();
+    final FieldBreakpoint fieldBreakpoint = FieldBreakpoint.create(myProject, field, object);
+    if (fieldBreakpoint != null) {
+      addBreakpoint(fieldBreakpoint);
+    }
+    return fieldBreakpoint;
+  }
+
+  @Nullable
+  public FieldBreakpoint addFieldBreakpoint(@NotNull Document document, int offset) {
+    PsiField field = FieldBreakpoint.findField(myProject, document, offset);
+    if (field == null) {
+      return null;
+    }
+
+    int line = document.getLineNumber(offset);
+
+    if (document.getLineNumber(field.getNameIdentifier().getTextOffset()) < line) {
+      return null;
+    }
+
+    return addFieldBreakpoint(document, line, field.getName());
+  }
+
+  @Nullable
+  public FieldBreakpoint addFieldBreakpoint(Document document, int lineIndex, String fieldName) {
+    ApplicationManager.getApplication().assertIsDispatchThread();
+    FieldBreakpoint fieldBreakpoint = FieldBreakpoint.create(myProject, document, lineIndex, fieldName);
+    if (fieldBreakpoint != null) {
+      addBreakpoint(fieldBreakpoint);
+    }
+    return fieldBreakpoint;
+  }
+
+  @NotNull
+  public ExceptionBreakpoint addExceptionBreakpoint(@NotNull String exceptionClassName, String packageName) {
+    ApplicationManager.getApplication().assertIsDispatchThread();
+    ExceptionBreakpoint breakpoint = new ExceptionBreakpoint(myProject, exceptionClassName, packageName);
+    addBreakpoint(breakpoint);
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("ExceptionBreakpoint Added");
+    }
+    return breakpoint;
+  }
+
+  @Nullable
+  public MethodBreakpoint addMethodBreakpoint(Document document, int lineIndex) {
+    ApplicationManager.getApplication().assertIsDispatchThread();
+
+    MethodBreakpoint breakpoint = MethodBreakpoint.create(myProject, document, lineIndex);
+    if (breakpoint == null) {
+      return null;
+    }
+
+    XDebugSessionImpl.NOTIFICATION_GROUP.createNotification("Method breakpoints may dramatically slow down debugging", MessageType.WARNING).notify(myProject);
+
+    addBreakpoint(breakpoint);
+    return breakpoint;
+  }
+
+  @Nullable
+  public WildcardMethodBreakpoint addMethodBreakpoint(String classPattern, String methodName) {
+    ApplicationManager.getApplication().assertIsDispatchThread();
+    WildcardMethodBreakpoint breakpoint = WildcardMethodBreakpoint.create(myProject, classPattern, methodName);
+    if (breakpoint == null) {
+      return null;
+    }
+    addBreakpoint(breakpoint);
+    return breakpoint;
+  }
+
+  /**
+   * @return null if not found or a breakpoint object
+   */
+  @NotNull
+  public List<BreakpointWithHighlighter> findBreakpoints(final Document document, final int offset) {
+    LinkedList<BreakpointWithHighlighter> result = new LinkedList<BreakpointWithHighlighter>();
+
+    ApplicationManager.getApplication().assertIsDispatchThread();
+    for (final Breakpoint breakpoint : getBreakpoints()) {
+      if (breakpoint instanceof BreakpointWithHighlighter && ((BreakpointWithHighlighter)breakpoint).isAt(document, offset)) {
+        result.add((BreakpointWithHighlighter)breakpoint);
+      }
+    }
+
+    return result;
+  }
+
+  @NotNull
+  public List<BreakpointWithHighlighter> findBreakpoints(@NotNull Document document, @NotNull TextRange textRange) {
+    ApplicationManager.getApplication().assertIsDispatchThread();
+    List<BreakpointWithHighlighter> result = new ArrayList<BreakpointWithHighlighter>();
+    int startLine = document.getLineNumber(textRange.getStartOffset());
+    int endLine = document.getLineNumber(textRange.getEndOffset())+1;
+    TextRange lineRange = new TextRange(startLine, endLine);
+    for (final Breakpoint breakpoint : getBreakpoints()) {
+      if (breakpoint instanceof BreakpointWithHighlighter &&
+          lineRange.contains(((BreakpointWithHighlighter)breakpoint).getLineIndex())) {
+        result.add((BreakpointWithHighlighter)breakpoint);
+      }
+    }
+
+    return result;
+  }
+
+  /**
+   * 
+   * @param document
+   * @param offset
+   * @param category breakpoint's category, null if the category does not matter
+   * @return
+   */
+  @Nullable
+  public <T extends BreakpointWithHighlighter> T findBreakpoint(final Document document, final int offset, @Nullable final Key<T> category) {
+    ApplicationManager.getApplication().assertIsDispatchThread();
+    for (final Breakpoint breakpoint : getBreakpoints()) {
+      if (breakpoint instanceof BreakpointWithHighlighter && ((BreakpointWithHighlighter)breakpoint).isAt(document, offset)) {
+        if (category == null || category.equals(breakpoint.getCategory())) {
+          return (T)breakpoint;
+        }
+      }
+    }
+    return null;
+  }
+
+  @Override
+  public void readExternal(@NotNull final Element parentNode) throws InvalidDataException {
+    if (myProject.isOpen()) {
+      doRead(parentNode);
+    } else {
+      myStartupManager.registerPostStartupActivity(new Runnable() {
+        @Override
+        public void run() {
+          doRead(parentNode);
+        }
+      });
+    }
+  }
+
+  private void doRead(@NotNull final Element parentNode) {
+    ApplicationManager.getApplication().runReadAction(new Runnable() {
+      @Override
+      @SuppressWarnings({"HardCodedStringLiteral"})
+      public void run() {
+        final Map<String, Breakpoint> nameToBreakpointMap = new java.util.HashMap<String, Breakpoint>();
+        try {
+          final List groups = parentNode.getChildren();
+          for (final Object group1 : groups) {
+            final Element group = (Element)group1;
+            if (group.getName().equals(RULES_GROUP_NAME)) {
+              continue;
+            }
+            final String categoryName = group.getName();
+            final Key<Breakpoint> breakpointCategory = BreakpointCategory.lookup(categoryName);
+            final String defaultPolicy = group.getAttributeValue(DEFAULT_SUSPEND_POLICY_ATTRIBUTE_NAME);
+            final boolean conditionEnabled = Boolean.parseBoolean(group.getAttributeValue(DEFAULT_CONDITION_STATE_ATTRIBUTE_NAME, "true"));
+            setBreakpointDefaults(breakpointCategory, new BreakpointDefaults(defaultPolicy, conditionEnabled));
+            Element anyExceptionBreakpointGroup;
+            if (!AnyExceptionBreakpoint.ANY_EXCEPTION_BREAKPOINT.equals(breakpointCategory)) {
+              // for compatibility with previous format
+              anyExceptionBreakpointGroup = group.getChild(AnyExceptionBreakpoint.ANY_EXCEPTION_BREAKPOINT.toString());
+              final BreakpointFactory factory = BreakpointFactory.getInstance(breakpointCategory);
+              if (factory != null) {
+                for (final Object o : group.getChildren("breakpoint")) {
+                  Element breakpointNode = (Element)o;
+                  Breakpoint breakpoint = factory.createBreakpoint(myProject, breakpointNode);
+                  breakpoint.readExternal(breakpointNode);
+                  addBreakpoint(breakpoint);
+                  nameToBreakpointMap.put(breakpoint.getDisplayName(), breakpoint);
+                }
+              }
+            }
+            else {
+              anyExceptionBreakpointGroup = group;
+            }
+
+            if (anyExceptionBreakpointGroup != null) {
+              final Element breakpointElement = group.getChild("breakpoint");
+              if (breakpointElement != null) {
+                getAnyExceptionBreakpoint().readExternal(breakpointElement);
+              }
+            }
+
+          }
+        }
+        catch (InvalidDataException ignored) {
+        }
+
+        final Element rulesGroup = parentNode.getChild(RULES_GROUP_NAME);
+        if (rulesGroup != null) {
+          final List rules = rulesGroup.getChildren("rule");
+          for (final Object rule1 : rules) {
+            final Element rule = (Element)rule1;
+            final Element master = rule.getChild(MASTER_BREAKPOINT_TAGNAME);
+            if (master == null) {
+              continue;
+            }
+            final Element slave = rule.getChild(SLAVE_BREAKPOINT_TAGNAME);
+            if (slave == null) {
+              continue;
+            }
+            final Breakpoint masterBreakpoint = nameToBreakpointMap.get(master.getAttributeValue("name"));
+            if (masterBreakpoint == null) {
+              continue;
+            }
+            final Breakpoint slaveBreakpoint = nameToBreakpointMap.get(slave.getAttributeValue("name"));
+            if (slaveBreakpoint == null) {
+              continue;
+            }
+            addBreakpointRule(new EnableBreakpointRule(BreakpointManager.this, masterBreakpoint, slaveBreakpoint, "true".equalsIgnoreCase(rule.getAttributeValue("leaveEnabled"))));
+          }
+        }
+
+        DebuggerInvocationUtil.invokeLater(myProject, new Runnable() {
+          @Override
+          public void run() {
+            updateBreakpointsUI();
+          }
+        });
+      }
+    });
+
+    myUIProperties.clear();
+    final Element props = parentNode.getChild("ui_properties");
+    if (props != null) {
+      final List children = props.getChildren("property");
+      for (Object child : children) {
+        Element property = (Element)child;
+        final String name = property.getAttributeValue("name");
+        final String value = property.getAttributeValue("value");
+        if (name != null && value != null) {
+          myUIProperties.put(name, value);
+        }
+      }
+    }
+  }
+
+  //used in Fabrique
+  public synchronized void addBreakpoint(Breakpoint breakpoint) {
+    myBreakpoints.add(breakpoint);
+    myBreakpointsListForIteration = null;
+    if(breakpoint instanceof BreakpointWithHighlighter) {
+      BreakpointWithHighlighter breakpointWithHighlighter = (BreakpointWithHighlighter)breakpoint;
+      Document document = breakpointWithHighlighter.getDocument();
+      if(document != null) {
+        List<BreakpointWithHighlighter> breakpoints = myDocumentBreakpoints.get(document);
+
+        if(breakpoints == null) {
+          breakpoints = new ArrayList<BreakpointWithHighlighter>();
+          myDocumentBreakpoints.put(document, breakpoints);
+        }
+        breakpoints.add(breakpointWithHighlighter);
+      }
+    }
+    myDispatcher.getMulticaster().breakpointsChanged();
+  }
+
+  public synchronized void removeBreakpoint(@Nullable final Breakpoint breakpoint) {
+    ApplicationManager.getApplication().assertIsDispatchThread();
+    if (breakpoint == null) {
+      return;
+    }
+
+    if (myBreakpoints.remove(breakpoint)) {
+      updateBreakpointRules(breakpoint);
+      myBreakpointsListForIteration = null;
+      if(breakpoint instanceof BreakpointWithHighlighter) {
+        //breakpoint.saveToString() may be invalid
+
+        for (final Document document : myDocumentBreakpoints.keySet()) {
+          final List<BreakpointWithHighlighter> documentBreakpoints = myDocumentBreakpoints.get(document);
+          final boolean reallyRemoved = documentBreakpoints.remove(breakpoint);
+          if (reallyRemoved) {
+            if (documentBreakpoints.isEmpty()) {
+              myDocumentBreakpoints.remove(document);
+            }
+            break;
+          }
+        }
+      }
+      //we delete breakpoints inside release, so gutter will not fire events to deleted breakpoints
+      breakpoint.delete();
+
+      myDispatcher.getMulticaster().breakpointsChanged();
+    }
+  }
+
+  @Override
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  public void writeExternal(@NotNull final Element parentNode) throws WriteExternalException {
+    WriteExternalException ex = ApplicationManager.getApplication().runReadAction(new Computable<WriteExternalException>() {
+      @Override
+      @Nullable
+      public WriteExternalException compute() {
+        try {
+          removeInvalidBreakpoints();
+          final Map<Key<? extends Breakpoint>, Element> categoryToElementMap = new java.util.HashMap<Key<? extends Breakpoint>, Element>();
+          for (Key<? extends Breakpoint> category : myBreakpointDefaults.keySet()) {
+            final Element group = getCategoryGroupElement(categoryToElementMap, category, parentNode);
+            final BreakpointDefaults defaults = getBreakpointDefaults(category);
+            group.setAttribute(DEFAULT_SUSPEND_POLICY_ATTRIBUTE_NAME, String.valueOf(defaults.getSuspendPolicy()));
+            group.setAttribute(DEFAULT_CONDITION_STATE_ATTRIBUTE_NAME, String.valueOf(defaults.isConditionEnabled()));
+          }
+          for (final Breakpoint breakpoint : getBreakpoints()) {
+            final Key<? extends Breakpoint> category = breakpoint.getCategory();
+            final Element group = getCategoryGroupElement(categoryToElementMap, category, parentNode);
+            if (breakpoint.isValid()) {
+              writeBreakpoint(group, breakpoint);
+            }
+          }
+          final AnyExceptionBreakpoint anyExceptionBreakpoint = getAnyExceptionBreakpoint();
+          final Element group = getCategoryGroupElement(categoryToElementMap, anyExceptionBreakpoint.getCategory(), parentNode);
+          writeBreakpoint(group, anyExceptionBreakpoint);
+          
+          final Element rules = new Element(RULES_GROUP_NAME);
+          parentNode.addContent(rules);
+          for (final EnableBreakpointRule myBreakpointRule : myBreakpointRules) {
+            writeRule(myBreakpointRule, rules);
+          }
+
+          return null;
+        }
+        catch (WriteExternalException e) {
+          return e;
+        }
+      }
+    });
+    if (ex != null) {
+      throw ex;
+    }
+    
+    final Element props = new Element("ui_properties");
+    parentNode.addContent(props);
+    for (final String name : myUIProperties.keySet()) {
+      final String value = myUIProperties.get(name);
+      final Element property = new Element("property");
+      props.addContent(property);
+      property.setAttribute("name", name);
+      property.setAttribute("value", value);
+    }
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"}) private static void writeRule(@NotNull final EnableBreakpointRule enableBreakpointRule, @NotNull Element element) {
+    Element rule = new Element("rule");
+    if (enableBreakpointRule.isLeaveEnabled()) {
+      rule.setAttribute("leaveEnabled", Boolean.toString(true));
+    }
+    element.addContent(rule);
+    writeRuleBreakpoint(rule, MASTER_BREAKPOINT_TAGNAME, enableBreakpointRule.getMasterBreakpoint());
+    writeRuleBreakpoint(rule, SLAVE_BREAKPOINT_TAGNAME, enableBreakpointRule.getSlaveBreakpoint());
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"}) private static void writeRuleBreakpoint(@NotNull final Element element, final String tagName, @NotNull final Breakpoint breakpoint) {
+    Element master = new Element(tagName);
+    element.addContent(master);
+    master.setAttribute("name", breakpoint.getDisplayName());
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  private static void writeBreakpoint(@NotNull final Element group, @NotNull final Breakpoint breakpoint) throws WriteExternalException {
+    Element breakpointNode = new Element("breakpoint");
+    group.addContent(breakpointNode);
+    breakpoint.writeExternal(breakpointNode);
+  }
+
+  private static <T extends Breakpoint> Element getCategoryGroupElement(@NotNull final Map<Key<? extends Breakpoint>, Element> categoryToElementMap, @NotNull final Key<T> category, @NotNull final Element parentNode) {
+    Element group = categoryToElementMap.get(category);
+    if (group == null) {
+      group = new Element(category.toString());
+      categoryToElementMap.put(category, group);
+      parentNode.addContent(group);
+    }
+    return group;
+  }
+
+  private void removeInvalidBreakpoints() {
+    ArrayList<Breakpoint> toDelete = new ArrayList<Breakpoint>();
+
+    for (Breakpoint breakpoint : getBreakpoints()) {
+      if (!breakpoint.isValid()) {
+        toDelete.add(breakpoint);
+      }
+    }
+
+    for (final Breakpoint aToDelete : toDelete) {
+      removeBreakpoint(aToDelete);
+    }
+  }
+
+  /**
+   * @return breakpoints of one of the category:
+   *         LINE_BREAKPOINTS, EXCEPTION_BREKPOINTS, FIELD_BREAKPOINTS, METHOD_BREAKPOINTS
+   */
+  public <T extends Breakpoint> Breakpoint[] getBreakpoints(@NotNull final Key<T> category) {
+    ApplicationManager.getApplication().assertIsDispatchThread();
+    removeInvalidBreakpoints();
+
+    final ArrayList<Breakpoint> breakpoints = new ArrayList<Breakpoint>();
+
+    for (Breakpoint breakpoint : getBreakpoints()) {
+      if (category.equals(breakpoint.getCategory())) {
+        breakpoints.add(breakpoint);
+      }
+    }
+
+    return breakpoints.toArray(new Breakpoint[breakpoints.size()]);
+  }
+
+  @NotNull
+  public synchronized List<Breakpoint> getBreakpoints() {
+    if (myBreakpointsListForIteration == null) {
+      myBreakpointsListForIteration = new ArrayList<Breakpoint>(myBreakpoints.size() + 1);
+      myBreakpointsListForIteration.addAll(myBreakpoints);
+      myBreakpointsListForIteration.add(getAnyExceptionBreakpoint());
+    }
+    return myBreakpointsListForIteration;
+  }
+
+  public AnyExceptionBreakpoint getAnyExceptionBreakpoint() {
+    if (myAnyExceptionBreakpoint == null) {
+      myAnyExceptionBreakpoint = new AnyExceptionBreakpoint(myProject);
+    }
+    return myAnyExceptionBreakpoint;
+  }
+
+  //interaction with RequestManagerImpl
+  public void disableBreakpoints(@NotNull final DebugProcessImpl debugProcess) {
+    final List<Breakpoint> breakpoints = getBreakpoints();
+    if (!breakpoints.isEmpty()) {
+      final RequestManagerImpl requestManager = debugProcess.getRequestsManager();
+      for (Breakpoint breakpoint : breakpoints) {
+        breakpoint.markVerified(requestManager.isVerified(breakpoint));
+        requestManager.deleteRequest(breakpoint);
+      }
+      SwingUtilities.invokeLater(new Runnable() {
+        @Override
+        public void run() {
+          updateBreakpointsUI();
+        }
+      });
+    }
+  }
+
+  public void enableBreakpoints(final DebugProcessImpl debugProcess) {
+    final List<Breakpoint> breakpoints = getBreakpoints();
+    if (!breakpoints.isEmpty()) {
+      for (Breakpoint breakpoint : breakpoints) {
+        breakpoint.markVerified(false); // clean cached state
+        breakpoint.createRequest(debugProcess);
+      }
+      SwingUtilities.invokeLater(new Runnable() {
+        @Override
+        public void run() {
+          updateBreakpointsUI();
+        }
+      });
+    }
+  }
+
+  public void applyThreadFilter(@NotNull final DebugProcessImpl debugProcess, @Nullable ThreadReference newFilterThread) {
+    final RequestManagerImpl requestManager = debugProcess.getRequestsManager();
+    final ThreadReference oldFilterThread = requestManager.getFilterThread();
+    if (Comparing.equal(newFilterThread, oldFilterThread)) {
+      // the filter already added
+      return;
+    }
+    requestManager.setFilterThread(newFilterThread);
+    if (newFilterThread == null || oldFilterThread != null) {
+      final List<Breakpoint> breakpoints = getBreakpoints();
+      for (Breakpoint breakpoint : breakpoints) {
+        if (LineBreakpoint.CATEGORY.equals(breakpoint.getCategory()) || MethodBreakpoint.CATEGORY.equals(breakpoint.getCategory())) {
+          requestManager.deleteRequest(breakpoint);
+          breakpoint.createRequest(debugProcess);
+        }
+      }
+    }
+    else {
+      // important! need to add filter to _existing_ requests, otherwise Requestor->Request mapping will be lost
+      // and debugger trees will not be restored to original state
+      abstract class FilterSetter <T extends EventRequest> {
+         void applyFilter(@NotNull final List<T> requests, final ThreadReference thread) {
+          for (T request : requests) {
+            try {
+              final boolean wasEnabled = request.isEnabled();
+              if (wasEnabled) {
+                request.disable();
+              }
+              addFilter(request, thread);
+              if (wasEnabled) {
+                request.enable();
+              }
+            }
+            catch (InternalException e) {
+              LOG.info(e);
+            }
+          }
+        }
+        protected abstract void addFilter(final T request, final ThreadReference thread);
+      }
+
+      final EventRequestManager eventRequestManager = requestManager.getVMRequestManager();
+
+      new FilterSetter<BreakpointRequest>() {
+        @Override
+        protected void addFilter(@NotNull final BreakpointRequest request, final ThreadReference thread) {
+          request.addThreadFilter(thread);
+        }
+      }.applyFilter(eventRequestManager.breakpointRequests(), newFilterThread);
+
+      new FilterSetter<MethodEntryRequest>() {
+        @Override
+        protected void addFilter(@NotNull final MethodEntryRequest request, final ThreadReference thread) {
+          request.addThreadFilter(thread);
+        }
+      }.applyFilter(eventRequestManager.methodEntryRequests(), newFilterThread);
+
+      new FilterSetter<MethodExitRequest>() {
+        @Override
+        protected void addFilter(@NotNull final MethodExitRequest request, final ThreadReference thread) {
+          request.addThreadFilter(thread);
+        }
+      }.applyFilter(eventRequestManager.methodExitRequests(), newFilterThread);
+    }
+  }
+
+  public void updateBreakpoints(final DebugProcessImpl debugProcess) {
+    List<Breakpoint> breakpoints = getBreakpoints();
+    for (Breakpoint breakpoint : breakpoints) {
+      RequestManagerImpl.updateRequests(breakpoint);
+    }
+  }
+
+  public void updateAllRequests() {
+    ApplicationManager.getApplication().assertIsDispatchThread();
+
+    List<Breakpoint> breakpoints = getBreakpoints();
+    for (Breakpoint breakpoint : breakpoints) {
+      fireBreakpointChanged(breakpoint);
+    }
+  }
+
+  public void updateBreakpointsUI() {
+    ApplicationManager.getApplication().assertIsDispatchThread();
+    for (Breakpoint breakpoint : getBreakpoints()) {
+      breakpoint.updateUI();
+    }
+  }
+
+  public void reloadBreakpoints() {
+    ApplicationManager.getApplication().assertIsDispatchThread();
+
+    for (Breakpoint breakpoint : getBreakpoints()) {
+      breakpoint.reload();
+    }
+  }
+
+  public void addBreakpointManagerListener(@NotNull BreakpointManagerListener listener) {
+    myDispatcher.addListener(listener);
+  }
+
+  public void removeBreakpointManagerListener(@NotNull BreakpointManagerListener listener) {
+    myDispatcher.removeListener(listener);
+  }
+
+  
+  private boolean myAllowMulticasting = true;
+  private final Alarm myAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD);
+  public void fireBreakpointChanged(Breakpoint breakpoint) {
+    RequestManagerImpl.updateRequests(breakpoint);
+    if (myAllowMulticasting) {
+      // can be invoked from non-AWT thread
+      myAlarm.cancelAllRequests();
+      final Runnable runnable = new Runnable() {
+        @Override
+        public void run() {
+          myAlarm.addRequest(new Runnable() {
+            @Override
+            public void run() {
+              myDispatcher.getMulticaster().breakpointsChanged();
+            }
+          }, 100);
+        }
+      };
+      if (ApplicationManager.getApplication().isDispatchThread()) {
+        runnable.run();
+      }
+      else {
+        SwingUtilities.invokeLater(runnable);
+      }
+    }
+  }
+
+  public void setBreakpointEnabled(@NotNull final Breakpoint breakpoint, final boolean enabled) {
+    if (breakpoint.ENABLED != enabled) {
+      breakpoint.ENABLED = enabled;
+      fireBreakpointChanged(breakpoint);
+      breakpoint.updateUI();
+    }
+  }
+  
+  public void addBreakpointRule(@NotNull EnableBreakpointRule rule) {
+    rule.init();
+    myBreakpointRules.add(rule);
+  }
+  
+  public boolean removeBreakpointRule(@NotNull EnableBreakpointRule rule) {
+    final boolean removed = myBreakpointRules.remove(rule);
+    if (removed) {
+      rule.dispose();
+    }
+    return removed;
+  }
+  
+  public boolean removeBreakpointRule(@NotNull Breakpoint slaveBreakpoint) {
+    for (final EnableBreakpointRule rule : myBreakpointRules) {
+      if (slaveBreakpoint.equals(rule.getSlaveBreakpoint())) {
+        removeBreakpointRule(rule);
+        return true;
+      }
+    }
+    return false;
+  }
+
+  private void updateBreakpointRules(@NotNull Breakpoint removedBreakpoint) {
+    for (Iterator<EnableBreakpointRule> it = myBreakpointRules.iterator(); it.hasNext();) {
+      final EnableBreakpointRule rule = it.next();
+      if (removedBreakpoint.equals(rule.getMasterBreakpoint()) || removedBreakpoint.equals(rule.getSlaveBreakpoint())) {
+        it.remove();
+      }
+    }
+  }
+
+  public void processBreakpointHit(@NotNull final Breakpoint breakpoint) {
+    for (final EnableBreakpointRule rule : myBreakpointRules) {
+      rule.processBreakpointHit(breakpoint);
+    }
+  }
+
+  public void setInitialBreakpointsState() {
+    myAllowMulticasting = false;
+    for (final EnableBreakpointRule myBreakpointRule : myBreakpointRules) {
+      myBreakpointRule.init();
+    }
+    myAllowMulticasting = true;
+    if (!myBreakpointRules.isEmpty()) {
+      IJSwingUtilities.invoke(new Runnable() {
+        @Override
+        public void run() {
+          myDispatcher.getMulticaster().breakpointsChanged();
+        }
+      });
+    }
+  }
+  
+  @Nullable
+  public Breakpoint findMasterBreakpoint(@NotNull Breakpoint dependentBreakpoint) {
+    for (final EnableBreakpointRule rule : myBreakpointRules) {
+      if (dependentBreakpoint.equals(rule.getSlaveBreakpoint())) {
+        return rule.getMasterBreakpoint();
+      }
+    }
+    return null;
+  }
+
+  @Nullable
+  public EnableBreakpointRule findBreakpointRule(@NotNull Breakpoint dependentBreakpoint) {
+    for (final EnableBreakpointRule rule : myBreakpointRules) {
+      if (dependentBreakpoint.equals(rule.getSlaveBreakpoint())) {
+        return rule;
+      }
+    }
+    return null;
+  }
+
+  public String getProperty(String name) {
+    return myUIProperties.get(name);
+  }
+  
+  public String setProperty(String name, String value) {
+    return myUIProperties.put(name, value);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointManagerListener.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointManagerListener.java
new file mode 100644
index 0000000..8d84aeb
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointManagerListener.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.breakpoints;
+
+import java.util.EventListener;
+
+public interface BreakpointManagerListener extends EventListener{
+  void breakpointsChanged ();
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointNameCellRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointNameCellRenderer.java
new file mode 100644
index 0000000..eac638e
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointNameCellRenderer.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.breakpoints;
+
+import com.intellij.util.ui.UIUtil;
+
+import javax.swing.*;
+import javax.swing.table.DefaultTableCellRenderer;
+import java.awt.*;
+
+/**
+ * @author Jeka
+ */
+public class BreakpointNameCellRenderer extends DefaultTableCellRenderer {
+  private final Color myAnyExceptionForeground = new Color(128, 0, 0);
+
+  public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+    super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
+    setBorder(null);
+    BreakpointTableModel tableModel = (BreakpointTableModel)table.getModel();
+    Breakpoint breakpoint = tableModel.getBreakpoint(row);
+    if (breakpoint == null){
+      return this;
+    };
+    final Icon icon = (breakpoint instanceof BreakpointWithHighlighter)?
+                      breakpoint.ENABLED? ((BreakpointWithHighlighter)breakpoint).getSetIcon(false) : ((BreakpointWithHighlighter)breakpoint).getDisabledIcon(
+                        false) : breakpoint.getIcon();
+    setIcon(icon);
+    setDisabledIcon(icon);
+
+    if(isSelected){
+      setForeground(UIUtil.getTableSelectionForeground());
+    }
+    else{
+      Color foreColor;
+      if(breakpoint instanceof AnyExceptionBreakpoint){
+        foreColor = myAnyExceptionForeground;
+      }
+      else{
+        foreColor = UIUtil.getTableForeground();
+      }
+      setForeground(foreColor);
+    }
+    setEnabled(isSelected || breakpoint.ENABLED);
+    return this;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointPanel.form b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointPanel.form
new file mode 100644
index 0000000..ff8bf76
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointPanel.form
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.debugger.ui.breakpoints.BreakpointPanel">
+  <grid id="800c4" binding="myPanel" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+    <margin top="0" left="0" bottom="0" right="0"/>
+    <constraints>
+      <xy x="42" y="71" width="312" height="181"/>
+    </constraints>
+    <properties/>
+    <border type="none"/>
+    <children>
+      <grid id="9a369" binding="myBreakPointsPanel" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="7" vgap="-1">
+        <margin top="0" left="5" bottom="5" right="5"/>
+        <constraints>
+          <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties/>
+        <border type="none"/>
+        <children>
+          <xy id="c9dc2" binding="myTablePlace" layout-manager="XYLayout" hgap="-1" vgap="-1">
+            <margin top="0" left="0" bottom="0" right="0"/>
+            <constraints>
+              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties/>
+            <border type="none"/>
+            <children/>
+          </xy>
+          <xy id="73b7b" binding="myButtonsPanel" layout-manager="XYLayout" hgap="-1" vgap="-1">
+            <margin top="0" left="0" bottom="0" right="0"/>
+            <constraints>
+              <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties/>
+            <border type="none"/>
+            <children/>
+          </xy>
+        </children>
+      </grid>
+      <xy id="96060" binding="myPropertiesPanelPlace" layout-manager="XYLayout" hgap="-1" vgap="-1">
+        <margin top="0" left="0" bottom="0" right="0"/>
+        <constraints>
+          <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties/>
+        <border type="empty">
+          <size top="0" left="5" bottom="5" right="5"/>
+        </border>
+        <children/>
+      </xy>
+    </children>
+  </grid>
+</form>
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointPanel.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointPanel.java
new file mode 100644
index 0000000..a19c9e5
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointPanel.java
@@ -0,0 +1,559 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.breakpoints;
+
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.ui.breakpoints.actions.BreakpointPanelAction;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.fileEditor.OpenFileDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Key;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiField;
+import com.intellij.ui.IdeBorderFactory;
+import com.intellij.ui.ScrollPaneFactory;
+import com.intellij.ui.SideBorder;
+import com.intellij.ui.TableUtil;
+import com.intellij.util.ui.UIUtil;
+import com.intellij.util.ui.tree.TreeUtil;
+import com.intellij.xdebugger.impl.breakpoints.ui.AbstractBreakpointPanel;
+import gnu.trove.TIntArrayList;
+import org.jetbrains.annotations.NonNls;
+
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.tree.TreeModel;
+import javax.swing.tree.TreePath;
+import javax.swing.tree.TreeSelectionModel;
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Jeka
+ */
+public class BreakpointPanel extends AbstractBreakpointPanel<Breakpoint> {
+  private final BreakpointPropertiesPanel myPropertiesPanel;
+  private final BreakpointPanelAction[] myActions;
+  private final Key<? extends Breakpoint> myBreakpointCategory;
+  private Breakpoint myCurrentViewableBreakpoint;
+  private final List<Runnable> myDisposeActions = new ArrayList<Runnable>();
+
+  private final Project myProject;
+  private JPanel myPanel;
+  private JPanel myBreakPointsPanel;
+  private JPanel myTablePlace;
+  private JPanel myPropertiesPanelPlace;
+  private final BreakpointTable myTable;
+  private final BreakpointTree myTree;
+  private JPanel myButtonsPanel;
+  private String myCurrentViewId = TABLE_VIEW;
+
+  private static final @NonNls String PROPERTIES_STUB = "STUB";
+  private static final @NonNls String PROPERTIES_DATA = "DATA";
+
+  public static final @NonNls String TREE_VIEW = "TREE";
+  public static final @NonNls String TABLE_VIEW = "TABLE";
+
+  public BreakpointPanel(final Project project,
+                         BreakpointPropertiesPanel propertiesPanel,
+                         final BreakpointPanelAction[] actions,
+                         Key<? extends Breakpoint> breakpointCategory,
+                         String tabName,
+                         String helpId) {
+    super(tabName, helpId, Breakpoint.class);
+    myProject = project;
+    myPropertiesPanel = propertiesPanel;
+    myActions = actions;
+    myBreakpointCategory = breakpointCategory;
+
+    myTable = new BreakpointTable(project);
+    myTree = new BreakpointTree(project);
+
+    myTablePlace.setLayout(new CardLayout());
+    JScrollPane pane = ScrollPaneFactory.createScrollPane(myTable);
+    pane.putClientProperty(UIUtil.KEEP_BORDER_SIDES, SideBorder.ALL);
+    myTablePlace.add(pane, TABLE_VIEW);
+
+    final ListSelectionListener listSelectionListener = new ListSelectionListener() {
+      public void valueChanged(ListSelectionEvent e) {
+        if (!e.getValueIsAdjusting()) {
+          updateCurrentBreakpointPropertiesPanel();
+        }
+      }
+    };
+    final ListSelectionModel tableSelectionModel = myTable.getSelectionModel();
+    tableSelectionModel.addListSelectionListener(listSelectionListener);
+    myDisposeActions.add(new Runnable() {
+      public void run() {
+        tableSelectionModel.removeListSelectionListener(listSelectionListener);
+      }
+    });
+
+    final TreeSelectionModel treeSelectionModel = myTree.getSelectionModel();
+    final TreeSelectionListener treeSelectionListener = new TreeSelectionListener() {
+      public void valueChanged(TreeSelectionEvent e) {
+        updateCurrentBreakpointPropertiesPanel();
+      }
+    };
+    treeSelectionModel.addTreeSelectionListener(treeSelectionListener);
+    myDisposeActions.add(new Runnable() {
+      public void run() {
+        treeSelectionModel.removeTreeSelectionListener(treeSelectionListener);
+      }
+    });
+
+    final BreakpointTableModel tableModel = myTable.getModel();
+    final TableModelListener tableModelListener = new TableModelListener() {
+      public void tableChanged(TableModelEvent e) {
+        if (e.getType() == TableModelEvent.UPDATE) {
+          updateCurrentBreakpointPropertiesPanel();
+        }
+        fireBreakpointsChanged();
+      }
+    };
+    tableModel.addTableModelListener(tableModelListener);
+    myDisposeActions.add(new Runnable() {
+      public void run() {
+        tableModel.removeTableModelListener(tableModelListener);
+      }
+    });
+
+
+    final TreeModel treeModel = myTree.getModel();
+    final TreeModelListener treeModelListener = new TreeModelListener() {
+      public void treeNodesChanged(TreeModelEvent e) {
+      }
+
+      public void treeNodesInserted(TreeModelEvent e) {
+      }
+
+      public void treeNodesRemoved(TreeModelEvent e) {
+      }
+
+      public void treeStructureChanged(TreeModelEvent e) {
+        SwingUtilities.invokeLater(new Runnable() {
+          public void run() {
+            ensureSelectionExists();
+            updateButtons();
+          }
+        });
+      }
+    };
+    treeModel.addTreeModelListener(treeModelListener);
+    myDisposeActions.add(new Runnable() {
+      public void run() {
+        treeModel.removeTreeModelListener(treeModelListener);
+      }
+    });
+
+    myPropertiesPanelPlace.setLayout(new CardLayout());
+    final JPanel stubPanel = new JPanel();
+    stubPanel.setMinimumSize(myPropertiesPanel.getPanel().getMinimumSize());
+    myPropertiesPanelPlace.add(stubPanel, PROPERTIES_STUB);
+    myPropertiesPanelPlace.add(myPropertiesPanel.getPanel(), PROPERTIES_DATA);
+
+    myBreakPointsPanel.setBorder(IdeBorderFactory.createEmptyBorder(6, 6, 0, 6));
+
+    myButtonsPanel.setLayout(new GridBagLayout());
+    for (int idx = 0; idx < actions.length; idx++) {
+      final BreakpointPanelAction action = actions[idx];
+      action.setPanel(this);
+      final AbstractButton button = action.isStateAction()? new JCheckBox(action.getName()) : new JButton(action.getName());
+      action.setButton(button);
+      button.addActionListener(action);
+      myDisposeActions.add(new Runnable() {
+        public void run() {
+          button.removeActionListener(action);
+        }
+      });
+      final double weighty = (idx == actions.length - 1) ? 1.0 : 0.0;
+      myButtonsPanel.add(button, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, weighty, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(0, 2, 2, 2), 0, 0));
+    }
+    final ListSelectionListener tableSelectionListener = new ListSelectionListener() {
+      public void valueChanged(ListSelectionEvent e) {
+        updateButtons();
+      }
+    };
+    tableSelectionModel.addListSelectionListener(tableSelectionListener);
+    myDisposeActions.add(new Runnable() {
+      public void run() {
+        tableSelectionModel.removeListSelectionListener(tableSelectionListener);
+      }
+    });
+
+    pane = ScrollPaneFactory.createScrollPane(myTree);
+    pane.putClientProperty(UIUtil.KEEP_BORDER_SIDES, SideBorder.ALL);
+    myTablePlace.add(pane, TREE_VIEW);
+
+    updateCurrentBreakpointPropertiesPanel();
+
+    final BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(project).getBreakpointManager();
+    final BreakpointManagerListener breakpointManagerListener = new BreakpointManagerListener() {
+      public void breakpointsChanged() {
+        if (isTreeShowing()) {
+          myTree.repaint();
+        }
+        else {
+          myTable.repaint();
+        }
+      }
+    };
+    breakpointManager.addBreakpointManagerListener(breakpointManagerListener);
+    myDisposeActions.add(new Runnable() {
+      public void run() {
+        breakpointManager.removeBreakpointManagerListener(breakpointManagerListener);
+      }
+    });
+  }
+
+  public BreakpointTable getTable() {
+    return myTable;
+  }
+
+  public BreakpointTree getTree() {
+    return myTree;
+  }
+
+  public void switchViews() {
+    final Breakpoint[] selectedBreakpoints = getSelectedBreakpoints();
+    showView(isTreeShowing() ? TABLE_VIEW : TREE_VIEW);
+    selectBreakpoints(selectedBreakpoints);
+  }
+
+  public void showView(final String viewId) {
+    if (TREE_VIEW.equals(viewId) || TABLE_VIEW.equals(viewId)) {
+      myCurrentViewId = viewId;
+      ((CardLayout)myTablePlace.getLayout()).show(myTablePlace, viewId);
+      updateButtons();
+      ensureSelectionExists();
+    }
+  }
+
+  public String getCurrentViewId() {
+    return myCurrentViewId;
+  }
+
+  public boolean isTreeShowing() {
+    return BreakpointPanel.TREE_VIEW.equals(getCurrentViewId());
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  public void setupPanelUI() {
+    final BreakpointManager breakpointManager = getBreakpointManager();
+    final Key<? extends Breakpoint> category = getBreakpointCategory();
+    final BreakpointTree tree = getTree();
+    final String flattenPackages = breakpointManager.getProperty(category + "_flattenPackages");
+    if (flattenPackages != null) {
+      tree.setFlattenPackages("true".equalsIgnoreCase(flattenPackages));
+    }
+    final String groupByClasses = breakpointManager.getProperty(category + "_groupByClasses");
+    if (groupByClasses != null) {
+      tree.setGroupByClasses("true".equalsIgnoreCase(groupByClasses));
+    }
+    final String groupByMethods = breakpointManager.getProperty(category + "_groupByMethods");
+    if (groupByMethods != null) {
+      tree.setGroupByMethods("true".equalsIgnoreCase(groupByMethods));
+    }
+
+    final String viewId = breakpointManager.getProperty(category + "_viewId");
+    if (viewId != null) {
+      showView(viewId);
+    }
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  public void savePanelSettings() {
+    Key<? extends Breakpoint> category = getBreakpointCategory();
+    final BreakpointManager breakpointManager = getBreakpointManager();
+
+    final BreakpointTree tree = getTree();
+    breakpointManager.setProperty(category + "_flattenPackages", tree.isFlattenPackages() ? "true" : "false");
+    breakpointManager.setProperty(category + "_groupByClasses", tree.isGroupByClasses() ? "true" : "false");
+    breakpointManager.setProperty(category + "_groupByMethods", tree.isGroupByMethods() ? "true" : "false");
+    breakpointManager.setProperty(category + "_viewId", getCurrentViewId());
+  }
+
+  protected BreakpointManager getBreakpointManager() {
+    return DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager();
+  }
+
+  private boolean hasEnabledBreakpoints() {
+    final List<Breakpoint> breakpoints = getBreakpoints();
+    for (Breakpoint breakpoint : breakpoints) {
+      if (breakpoint.ENABLED) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  public Icon getTabIcon() {
+    final BreakpointFactory factory = BreakpointFactory.getInstance(getBreakpointCategory());
+    return hasEnabledBreakpoints() ? factory.getIcon() : factory.getDisabledIcon();
+  }
+
+  public boolean canSelectBreakpoint(final Breakpoint breakpoint) {
+    return breakpoint.getCategory().equals(getBreakpointCategory());
+  }
+
+  public Key<? extends Breakpoint> getBreakpointCategory() {
+    return myBreakpointCategory;
+  }
+
+  public Breakpoint getCurrentViewableBreakpoint() {
+    return myCurrentViewableBreakpoint;
+  }
+
+  public void saveBreakpoints() {
+    if (myCurrentViewableBreakpoint != null) {
+      myPropertiesPanel.saveTo(myCurrentViewableBreakpoint, new Runnable() {
+        public void run() {
+          myTable.repaint();
+        }
+      });
+    }
+  }
+
+  public void updateButtons() {
+    for (final BreakpointPanelAction action : myActions) {
+      final AbstractButton button = action.getButton();
+      action.update();
+      if (!button.isEnabled() && button.hasFocus()) {
+        button.transferFocus();
+      }
+    }
+  }
+
+  public JPanel getPanel() {
+    return myPanel;
+  }
+
+  public void selectBreakpoint(Breakpoint breakpoint) {
+    if (isTreeShowing()) {
+      myTree.selectBreakpoint(breakpoint);
+    }
+    else {
+      int index = myTable.getModel().getBreakpointIndex(breakpoint);
+      ListSelectionModel model = myTable.getSelectionModel();
+      model.clearSelection();
+      model.addSelectionInterval(index, index);
+    }
+  }
+
+  @Override
+  public boolean hasBreakpoints() {
+    return getBreakpointManager().getBreakpoints(getBreakpointCategory()).length > 0;
+  }
+
+  public void selectBreakpoints(Breakpoint[] breakpoints) {
+    if (isTreeShowing()) {
+      myTree.selectBreakpoints(breakpoints);
+    }
+    else {
+      final TIntArrayList rows = new TIntArrayList(breakpoints.length);
+      for (Breakpoint breakpoint : breakpoints) {
+        final int index = myTable.getModel().getBreakpointIndex(breakpoint);
+        if (index >= 0) {
+          rows.add(index);
+        }
+      }
+      myTable.getSelectionModel().clearSelection();
+      TableUtil.selectRows(myTable, rows.toNativeArray());
+    }
+  }
+
+  public void resetBreakpoints() {
+    Breakpoint[] breakpoints = getBreakpointManager().getBreakpoints(getBreakpointCategory());
+    myTable.setBreakpoints(breakpoints);
+    myTree.setBreakpoints(breakpoints);
+    ensureSelectionExists();
+    updateButtons();
+  }
+
+  public Breakpoint[] getSelectedBreakpoints() {
+    return isTreeShowing() ? myTree.getSelectedBreakpoints() : myTable.getSelectedBreakpoints();
+  }
+
+  public void removeSelectedBreakpoints() {
+    final Breakpoint[] selectedBreakpoints = getSelectedBreakpoints();
+    if (selectedBreakpoints.length == 0) {
+      return;
+    }
+
+    final boolean inTreeMode = isTreeShowing();
+    
+    final int minSelectionIndex;
+    if (inTreeMode) {
+      minSelectionIndex = Math.max(0, myTree.getSelectionModel().getMinSelectionRow());
+    }
+    else {
+      minSelectionIndex = Math.max(0, myTable.getSelectionModel().getMinSelectionIndex());
+    }
+
+    myTree.removeBreakpoints(selectedBreakpoints);
+    myTable.getModel().removeBreakpoints(selectedBreakpoints);
+    myCurrentViewableBreakpoint = null;
+
+    if (inTreeMode) {
+      if (myTree.getRowCount() > 0) {
+        int rowToSelect = minSelectionIndex >= myTree.getRowCount()? myTree.getRowCount() - 1 : minSelectionIndex;
+        final TreePath path = myTree.getPathForRow(rowToSelect);
+        if (path != null) {
+          TreeUtil.selectPath(myTree, path, true);
+        }
+      }
+    }
+    else {
+      if (myTable.getRowCount() > 0) { // if in table mode and there are items to select
+        int indexToSelect = minSelectionIndex >= myTable.getRowCount()? myTable.getRowCount() - 1 : minSelectionIndex;
+        TableUtil.selectRows(myTable, new int[] {indexToSelect});
+      }
+    }
+
+    updateCurrentBreakpointPropertiesPanel();
+  }
+
+  public void insertBreakpointAt(Breakpoint breakpoint, int index) {
+    myTable.getModel().insertBreakpointAt(breakpoint, index);
+    myTree.addBreakpoint(breakpoint);
+    selectBreakpoint(breakpoint);
+  }
+
+  public void addBreakpoint(Breakpoint breakpoint) {
+    myTable.getModel().addBreakpoint(breakpoint);
+    myTree.addBreakpoint(breakpoint);
+    selectBreakpoint(breakpoint);
+  }
+
+  private void updateCurrentBreakpointPropertiesPanel() {
+    if (myCurrentViewableBreakpoint != null) {
+      myPropertiesPanel.saveTo(myCurrentViewableBreakpoint, new Runnable() {
+        public void run() {
+          if (isTreeShowing()) {
+            myTree.repaint();
+          }
+          else {
+            myTable.repaint();
+          }
+        }
+      });
+    }
+    Breakpoint[] breakpoints = getSelectedBreakpoints();
+    Breakpoint oldViewableBreakpoint = myCurrentViewableBreakpoint;
+    myCurrentViewableBreakpoint = (breakpoints != null && breakpoints.length == 1) ? breakpoints[0] : null;
+    if (myCurrentViewableBreakpoint != null) {
+      if (oldViewableBreakpoint == null) {
+        ((CardLayout)myPropertiesPanelPlace.getLayout()).show(myPropertiesPanelPlace, PROPERTIES_DATA);
+      }
+      myPropertiesPanel.initFrom(myCurrentViewableBreakpoint, true);
+    }
+    else {
+      ((CardLayout)myPropertiesPanelPlace.getLayout()).show(myPropertiesPanelPlace, PROPERTIES_STUB);
+    }
+    updateButtons();
+  }
+
+  public JComponent getControl(String control) {
+    return myPropertiesPanel.getControl(control);
+  }
+
+  public int getBreakpointCount() {
+    return myTable.getBreakpoints().size();
+  }
+
+  public final List<Breakpoint> getBreakpoints() {
+    return myTable.getBreakpoints();
+  }
+
+  public void dispose() {
+    savePanelSettings();
+    for (Runnable runnable : myDisposeActions) {
+      runnable.run();
+    }
+    myDisposeActions.clear();
+
+    myTree.dispose();
+
+    final KeyStroke[] tableStrokes = myTable.getRegisteredKeyStrokes();
+    for (KeyStroke stroke : tableStrokes) {
+      myTable.unregisterKeyboardAction(stroke);
+    }
+
+    myPropertiesPanel.dispose();
+  }
+
+  public OpenFileDescriptor createEditSourceDescriptor(final Project project) {
+    Breakpoint[] breakpoints = getSelectedBreakpoints();
+    if (breakpoints == null || breakpoints.length == 0) {
+      return null;
+    }
+    Breakpoint br = breakpoints[0];
+    int line;
+    Document doc;
+    if (br instanceof BreakpointWithHighlighter) {
+      BreakpointWithHighlighter breakpoint = (BreakpointWithHighlighter)br;
+      doc = breakpoint.getDocument();
+      line = breakpoint.getLineIndex();
+    }
+    else {
+      return null;
+    }
+    if (line < 0 || line >= doc.getLineCount()) {
+      return null;
+    }
+    int offset = doc.getLineStartOffset(line);
+    if(br instanceof FieldBreakpoint) {
+      PsiField field = ((FieldBreakpoint) br).getPsiField();
+      if(field != null) {
+        offset = field.getTextOffset();
+      }
+    }
+    VirtualFile vFile = FileDocumentManager.getInstance().getFile(doc);
+    if (vFile == null || !vFile.isValid()) {
+      return null;
+    }
+    return new OpenFileDescriptor(project, vFile, offset);
+  }
+
+  public void ensureSelectionExists() {
+    if (myTable.getRowCount() > 0 && myTable.getSelectedRow() < 0) {
+      ListSelectionModel model = myTable.getSelectionModel();
+      model.clearSelection();
+      model.addSelectionInterval(0, 0);
+    }
+
+    final List<Breakpoint> treeBreakpoints = myTree.getBreakpoints();
+    if (treeBreakpoints.size() > 0) {
+      if (myTree.getSelectionModel().getSelectionCount() == 0) {
+        myTree.selectFirstBreakpoint();
+      }
+    }
+
+    SwingUtilities.invokeLater(new Runnable() {
+      public void run() {
+        if (isTreeShowing()) {
+          myTree.requestFocus();
+        }
+        else {
+          myTable.requestFocus();
+        }
+      }
+    });
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointPropertiesPanel.form b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointPropertiesPanel.form
new file mode 100644
index 0000000..7d71e21
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointPropertiesPanel.form
@@ -0,0 +1,425 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.debugger.ui.breakpoints.BreakpointPropertiesPanel">
+  <grid id="6570" binding="myPanel" custom-create="true" layout-manager="GridLayoutManager" row-count="4" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+    <margin top="0" left="0" bottom="0" right="0"/>
+    <constraints>
+      <xy x="23" y="37" width="751" height="404"/>
+    </constraints>
+    <properties/>
+    <border type="none"/>
+    <children>
+      <grid id="7978d" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+        <margin top="0" left="0" bottom="0" right="0"/>
+        <constraints>
+          <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="1" fill="1" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties/>
+        <border type="none"/>
+        <children>
+          <xy id="f3049" binding="myConditionComboPanel" layout-manager="XYLayout" hgap="-1" vgap="-1">
+            <margin top="0" left="0" bottom="0" right="0"/>
+            <constraints>
+              <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties/>
+            <border type="none"/>
+            <children/>
+          </xy>
+          <component id="f3923" class="com.intellij.ui.components.JBCheckBox" binding="myConditionCheckbox">
+            <constraints>
+              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <text value="&amp;Condition"/>
+            </properties>
+          </component>
+        </children>
+      </grid>
+      <grid id="763d0" layout-manager="GridLayoutManager" row-count="1" column-count="5" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+        <margin top="0" left="0" bottom="0" right="0"/>
+        <constraints>
+          <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties/>
+        <clientProperties>
+          <BorderFactoryClass class="java.lang.String" value="com.intellij.ui.IdeBorderFactory$PlainSmallWithoutIndent"/>
+        </clientProperties>
+        <border type="none">
+          <font/>
+        </border>
+        <children>
+          <component id="f6192" class="javax.swing.JRadioButton" binding="myRbSuspendThread">
+            <constraints>
+              <grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <text resource-bundle="messages/DebuggerBundle" key="breakpoint.properties.panel.option.suspend.thread"/>
+            </properties>
+          </component>
+          <component id="106f5" class="javax.swing.JRadioButton" binding="myRbSuspendAll">
+            <constraints>
+              <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <text resource-bundle="messages/DebuggerBundle" key="breakpoint.properties.panel.option.suspend.all"/>
+            </properties>
+          </component>
+          <hspacer id="46ea8">
+            <constraints>
+              <grid row="0" column="3" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+            </constraints>
+          </hspacer>
+          <component id="be00d" class="javax.swing.JButton" binding="myMakeDefaultButton">
+            <constraints>
+              <grid row="0" column="4" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <text resource-bundle="messages/DebuggerBundle" key="breakpoint.properties.panel.option.suspend.default"/>
+            </properties>
+          </component>
+          <component id="cd928" class="com.intellij.ui.components.JBCheckBox" binding="myCbSuspend">
+            <constraints>
+              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <text value="&amp;Suspend"/>
+            </properties>
+          </component>
+        </children>
+      </grid>
+      <grid id="5aab2" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+        <margin top="0" left="0" bottom="0" right="0"/>
+        <constraints>
+          <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties/>
+        <border type="none"/>
+        <children>
+          <grid id="da86f" layout-manager="GridLayoutManager" row-count="4" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+            <margin top="0" left="0" bottom="0" right="0"/>
+            <constraints>
+              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false">
+                <preferred-size width="245" height="251"/>
+              </grid>
+            </constraints>
+            <properties/>
+            <border type="none"/>
+            <children>
+              <grid id="1d1c" binding="myActionsPanel" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+                <margin top="0" left="0" bottom="0" right="5"/>
+                <constraints>
+                  <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties/>
+                <clientProperties>
+                  <BorderFactoryClass class="java.lang.String" value="com.intellij.ui.IdeBorderFactory$PlainSmallWithoutIndent"/>
+                </clientProperties>
+                <border type="etched" title-resource-bundle="messages/DebuggerBundle" title-key="label.breakpoint.properties.panel.group.actions"/>
+                <children>
+                  <component id="185b0" class="javax.swing.JCheckBox" binding="myLogMessageCheckBox">
+                    <constraints>
+                      <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="7" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                    </constraints>
+                    <properties>
+                      <text resource-bundle="messages/DebuggerBundle" key="breakpoint.properties.panel.option.log.message"/>
+                    </properties>
+                  </component>
+                  <grid id="42168" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+                    <margin top="0" left="0" bottom="0" right="0"/>
+                    <constraints>
+                      <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="7" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+                    </constraints>
+                    <properties/>
+                    <border type="none"/>
+                    <children>
+                      <grid id="4a38" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+                        <margin top="0" left="0" bottom="0" right="0"/>
+                        <constraints>
+                          <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="1" fill="1" indent="0" use-parent-layout="false"/>
+                        </constraints>
+                        <properties/>
+                        <border type="none"/>
+                        <children>
+                          <hspacer id="9c54c">
+                            <constraints>
+                              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="1" hsize-policy="0" anchor="0" fill="1" indent="0" use-parent-layout="false">
+                                <preferred-size width="15" height="-1"/>
+                              </grid>
+                            </constraints>
+                          </hspacer>
+                          <grid id="80950" binding="myLogExpressionComboPanel" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+                            <margin top="0" left="0" bottom="0" right="0"/>
+                            <constraints>
+                              <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="7" anchor="1" fill="1" indent="0" use-parent-layout="false"/>
+                            </constraints>
+                            <properties/>
+                            <border type="none"/>
+                            <children/>
+                          </grid>
+                        </children>
+                      </grid>
+                      <component id="7b0ce" class="javax.swing.JCheckBox" binding="myLogExpressionCheckBox">
+                        <constraints>
+                          <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="7" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                        </constraints>
+                        <properties>
+                          <text resource-bundle="messages/DebuggerBundle" key="breakpoint.properties.panel.option.log.expression"/>
+                        </properties>
+                      </component>
+                    </children>
+                  </grid>
+                </children>
+              </grid>
+              <xy id="862d9" binding="mySpecialBoxPanel" layout-manager="XYLayout" hgap="-1" vgap="-1">
+                <margin top="0" left="0" bottom="0" right="0"/>
+                <constraints>
+                  <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties>
+                  <visible value="true"/>
+                </properties>
+                <border type="none"/>
+                <children/>
+              </xy>
+              <grid id="d7b0a" binding="myDependsOnPanel" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+                <margin top="0" left="0" bottom="0" right="0"/>
+                <constraints>
+                  <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties/>
+                <clientProperties>
+                  <BorderFactoryClass class="java.lang.String" value=""/>
+                </clientProperties>
+                <border type="empty"/>
+                <children>
+                  <grid id="4241e" layout-manager="GridLayoutManager" row-count="3" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+                    <margin top="0" left="0" bottom="0" right="5"/>
+                    <constraints>
+                      <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+                    </constraints>
+                    <properties/>
+                    <border type="none"/>
+                    <children>
+                      <grid id="9b21c" binding="myDependentBreakpointComboPanel" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+                        <margin top="0" left="15" bottom="0" right="0"/>
+                        <constraints>
+                          <grid row="1" column="0" row-span="1" col-span="3" vsize-policy="0" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+                        </constraints>
+                        <properties/>
+                        <border type="none"/>
+                        <children/>
+                      </grid>
+                      <component id="7f1f0" class="javax.swing.JLabel" binding="myEnableOrDisableLabel">
+                        <constraints>
+                          <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                        </constraints>
+                        <properties>
+                          <text resource-bundle="messages/DebuggerBundle" key="breakpoint.properties.panel.option.dependency.type.lable"/>
+                        </properties>
+                      </component>
+                      <component id="e3baf" class="javax.swing.JRadioButton" binding="myDisableAgainRadio" default-binding="true">
+                        <constraints>
+                          <grid row="2" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                        </constraints>
+                        <properties>
+                          <text resource-bundle="messages/DebuggerBundle" key="breakpoint.properties.panel.option.depends.disable.again"/>
+                        </properties>
+                      </component>
+                      <component id="10e41" class="javax.swing.JRadioButton" binding="myLeaveEnabledRadioButton" default-binding="true">
+                        <constraints>
+                          <grid row="2" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                        </constraints>
+                        <properties>
+                          <text resource-bundle="messages/DebuggerBundle" key="breakpoint.properties.panel.option.depends.leave.enabled"/>
+                        </properties>
+                      </component>
+                      <component id="f3672" class="com.intellij.ui.components.JBLabel">
+                        <constraints>
+                          <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                        </constraints>
+                        <properties>
+                          <text resource-bundle="messages/XDebuggerBundle" key="xbreakpoint.master.breakpoint.description"/>
+                        </properties>
+                      </component>
+                    </children>
+                  </grid>
+                </children>
+              </grid>
+              <vspacer id="21184">
+                <constraints>
+                  <grid row="3" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
+                </constraints>
+              </vspacer>
+            </children>
+          </grid>
+          <grid id="d03f5" binding="myConditionsPanel" layout-manager="GridLayoutManager" row-count="4" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="7">
+            <margin top="2" left="2" bottom="5" right="5"/>
+            <constraints>
+              <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties/>
+            <clientProperties>
+              <BorderFactoryClass class="java.lang.String" value="com.intellij.ui.IdeBorderFactory$PlainSmallWithoutIndent"/>
+            </clientProperties>
+            <border type="etched" title-resource-bundle="messages/DebuggerBundle" title-key="label.breakpoint.properties.panel.group.conditions"/>
+            <children>
+              <grid id="b404a" binding="myInstanceFiltersPanel" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="0">
+                <margin top="0" left="0" bottom="0" right="0"/>
+                <constraints>
+                  <grid row="0" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties/>
+                <border type="none"/>
+                <children>
+                  <component id="20b41" class="javax.swing.JCheckBox" binding="myInstanceFiltersCheckBox">
+                    <constraints>
+                      <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                    </constraints>
+                    <properties>
+                      <margin top="2" left="2" bottom="0" right="2"/>
+                      <text resource-bundle="messages/DebuggerBundle" key="breakpoint.properties.panel.option.instance.filters"/>
+                    </properties>
+                  </component>
+                  <grid id="d9be2" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+                    <margin top="0" left="0" bottom="0" right="0"/>
+                    <constraints>
+                      <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+                    </constraints>
+                    <properties/>
+                    <border type="none"/>
+                    <children>
+                      <hspacer id="e6448">
+                        <constraints>
+                          <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="1" hsize-policy="0" anchor="0" fill="1" indent="0" use-parent-layout="false">
+                            <preferred-size width="15" height="-1"/>
+                          </grid>
+                        </constraints>
+                      </hspacer>
+                      <xy id="1114b" binding="myInstanceFiltersFieldPanel" layout-manager="XYLayout" hgap="-1" vgap="-1">
+                        <margin top="0" left="0" bottom="0" right="0"/>
+                        <constraints>
+                          <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+                        </constraints>
+                        <properties/>
+                        <border type="none"/>
+                        <children/>
+                      </xy>
+                    </children>
+                  </grid>
+                </children>
+              </grid>
+              <grid id="f07fc" binding="myClassFiltersPanel" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="0">
+                <margin top="0" left="0" bottom="0" right="0"/>
+                <constraints>
+                  <grid row="1" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties/>
+                <border type="none"/>
+                <children>
+                  <component id="40e6b" class="javax.swing.JCheckBox" binding="myClassFiltersCheckBox">
+                    <constraints>
+                      <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                    </constraints>
+                    <properties>
+                      <margin top="2" left="2" bottom="0" right="2"/>
+                      <text resource-bundle="messages/DebuggerBundle" key="breakpoint.properties.panel.option.class.filters"/>
+                    </properties>
+                  </component>
+                  <grid id="fbeb4" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+                    <margin top="0" left="0" bottom="0" right="0"/>
+                    <constraints>
+                      <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+                    </constraints>
+                    <properties/>
+                    <border type="none"/>
+                    <children>
+                      <xy id="72d13" binding="myClassFiltersFieldPanel" layout-manager="XYLayout" hgap="-1" vgap="-1">
+                        <margin top="0" left="0" bottom="0" right="0"/>
+                        <constraints>
+                          <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+                        </constraints>
+                        <properties/>
+                        <border type="none"/>
+                        <children/>
+                      </xy>
+                      <hspacer id="1d45">
+                        <constraints>
+                          <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="1" hsize-policy="0" anchor="0" fill="1" indent="0" use-parent-layout="false">
+                            <preferred-size width="15" height="-1"/>
+                          </grid>
+                        </constraints>
+                      </hspacer>
+                    </children>
+                  </grid>
+                </children>
+              </grid>
+              <grid id="21edd" binding="myPassCountPanel" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="0">
+                <margin top="0" left="0" bottom="0" right="0"/>
+                <constraints>
+                  <grid row="2" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="7" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+                </constraints>
+                <properties/>
+                <border type="none"/>
+                <children>
+                  <component id="11e5a" class="javax.swing.JCheckBox" binding="myPassCountCheckbox">
+                    <constraints>
+                      <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+                    </constraints>
+                    <properties>
+                      <margin top="2" left="2" bottom="0" right="2"/>
+                      <text resource-bundle="messages/DebuggerBundle" key="breakpoint.properties.panel.option.pass.count"/>
+                    </properties>
+                  </component>
+                  <grid id="e8cc5" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+                    <margin top="0" left="0" bottom="0" right="0"/>
+                    <constraints>
+                      <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+                    </constraints>
+                    <properties/>
+                    <border type="none"/>
+                    <children>
+                      <component id="64df8" class="javax.swing.JTextField" binding="myPassCountField">
+                        <constraints>
+                          <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
+                            <preferred-size width="15" height="-1"/>
+                          </grid>
+                        </constraints>
+                        <properties>
+                          <enabled value="true"/>
+                          <horizontalAlignment value="10"/>
+                        </properties>
+                      </component>
+                      <hspacer id="9be08">
+                        <constraints>
+                          <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="1" hsize-policy="0" anchor="0" fill="1" indent="0" use-parent-layout="false">
+                            <preferred-size width="15" height="-1"/>
+                          </grid>
+                        </constraints>
+                      </hspacer>
+                    </children>
+                  </grid>
+                </children>
+              </grid>
+              <vspacer id="905e2">
+                <constraints>
+                  <grid row="3" column="1" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
+                </constraints>
+              </vspacer>
+            </children>
+          </grid>
+        </children>
+      </grid>
+      <vspacer id="62b02">
+        <constraints>
+          <grid row="3" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
+        </constraints>
+      </vspacer>
+    </children>
+  </grid>
+  <buttonGroups>
+    <group name="buttonGroup1">
+      <member id="e3baf"/>
+      <member id="10e41"/>
+    </group>
+  </buttonGroups>
+</form>
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointPropertiesPanel.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointPropertiesPanel.java
new file mode 100644
index 0000000..78abfe4
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointPropertiesPanel.java
@@ -0,0 +1,858 @@
+/*
+ * Copyright 2000-2012 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.
+ */
+
+/*
+ * Class BreakpointPropertiesPanel
+ * @author Jeka
+ */
+package com.intellij.debugger.ui.breakpoints;
+
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.InstanceFilter;
+import com.intellij.debugger.engine.evaluation.CodeFragmentKind;
+import com.intellij.debugger.engine.evaluation.DefaultCodeFragmentFactory;
+import com.intellij.debugger.engine.evaluation.TextWithImportsImpl;
+import com.intellij.debugger.settings.DebuggerSettings;
+import com.intellij.debugger.ui.CompletionEditor;
+import com.intellij.debugger.ui.DebuggerExpressionComboBox;
+import com.intellij.debugger.ui.DebuggerStatementEditor;
+import com.intellij.debugger.ui.JavaDebuggerSupport;
+import com.intellij.ide.util.ClassFilter;
+import com.intellij.openapi.editor.event.DocumentEvent;
+import com.intellij.openapi.editor.event.DocumentListener;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.openapi.ui.FixedSizeButton;
+import com.intellij.openapi.util.Key;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.wm.IdeFocusManager;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiElement;
+import com.intellij.ui.FieldPanel;
+import com.intellij.ui.MultiLineTooltipUI;
+import com.intellij.ui.components.JBCheckBox;
+import com.intellij.ui.popup.util.DetailView;
+import com.intellij.util.IJSwingUtilities;
+import com.intellij.xdebugger.impl.DebuggerSupport;
+import com.intellij.xdebugger.impl.breakpoints.ui.BreakpointChooser;
+import com.intellij.xdebugger.impl.breakpoints.ui.BreakpointItem;
+import com.intellij.xdebugger.impl.breakpoints.ui.BreakpointNoneItem;
+import com.intellij.xdebugger.impl.ui.DebuggerUIUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public abstract class BreakpointPropertiesPanel {
+
+  private BreakpointChooser myMasterBreakpointChooser;
+
+  public void setDetailView(DetailView detailView) {
+    myDetailView = detailView;
+    myMasterBreakpointChooser.setDetailView(detailView);
+  }
+
+  private DetailView myDetailView;
+
+  protected final Project myProject;
+  private final Key<? extends Breakpoint> myBreakpointCategory;
+  private boolean myCompact;
+  private JPanel myPanel;
+  private final DebuggerExpressionComboBox myConditionCombo;
+  private final DebuggerExpressionComboBox myLogExpressionCombo;
+  private JTextField myPassCountField;
+  private final FieldPanel myInstanceFiltersField;
+
+  private final FieldPanel myClassFiltersField;
+  private com.intellij.ui.classFilter.ClassFilter[] myClassFilters;
+  private com.intellij.ui.classFilter.ClassFilter[] myClassExclusionFilters;
+  private InstanceFilter[] myInstanceFilters;
+
+  private JCheckBox myLogExpressionCheckBox;
+  private JCheckBox myLogMessageCheckBox;
+  protected JCheckBox myPassCountCheckbox;
+  private JCheckBox myInstanceFiltersCheckBox;
+  private JCheckBox myClassFiltersCheckBox;
+
+  private JPanel myInstanceFiltersFieldPanel;
+  private JPanel myClassFiltersFieldPanel;
+  private JPanel myConditionComboPanel;
+  private JPanel myLogExpressionComboPanel;
+  private JPanel myDependentBreakpointComboPanel;
+  private JPanel mySpecialBoxPanel;
+  private PsiClass myBreakpointPsiClass;
+
+  private JRadioButton myRbSuspendThread;
+  private JRadioButton myRbSuspendAll;
+  private JBCheckBox myCbSuspend;
+  private JButton myMakeDefaultButton;
+
+  private JRadioButton myDisableAgainRadio;
+  private JRadioButton myLeaveEnabledRadioButton;
+
+  private JLabel myEnableOrDisableLabel;
+  private JPanel myDependsOnPanel;
+  private JPanel myInstanceFiltersPanel;
+  private JPanel myClassFiltersPanel;
+  private JPanel myPassCountPanel;
+  private JPanel myConditionsPanel;
+  private JPanel myActionsPanel;
+  private JBCheckBox myConditionCheckbox;
+
+  ButtonGroup mySuspendPolicyGroup;
+  public static final String CONTROL_LOG_MESSAGE = "logMessage";
+  private final FixedSizeButton myConditionMagnifierButton;
+  private boolean myMoreOptionsVisible = true;
+  private Breakpoint myBreakpoint;
+
+  public boolean isSaveOnRemove() {
+    return mySaveOnRemove;
+  }
+
+  public void setSaveOnRemove(boolean saveOnRemove) {
+    mySaveOnRemove = saveOnRemove;
+  }
+
+  private boolean mySaveOnRemove = false;
+
+  public boolean isMoreOptionsVisible() {
+    return myMoreOptionsVisible;
+  }
+
+  private void createUIComponents() {
+    myPanel = new JPanel() {
+      @Override
+      public void removeNotify() {
+        super.removeNotify();
+        if (mySaveOnRemove) {
+          saveTo(myBreakpoint, new Runnable() {
+            @Override
+            public void run() {}
+          });
+        }
+      }
+    };
+  }
+
+  public interface Delegate {
+
+    void showActionsPanel();
+  }
+  private Delegate myDelegate;
+
+  public JComponent getControl(String control) {
+    if(CONTROL_LOG_MESSAGE.equals(control)) {
+      return myLogExpressionCombo;
+    }
+    return null;
+  }
+
+  public void dispose() {
+    if (myConditionCombo != null) {
+      myConditionCombo.dispose();
+    }
+    if (myLogExpressionCombo != null) {
+      myLogExpressionCombo.dispose();
+    }
+  }
+
+  public void setActionsPanelVisible(boolean b) {
+    myActionsPanel.setVisible(b);
+  }
+
+  public void setMoreOptionsVisible(boolean b) {
+    myMoreOptionsVisible = b;
+    myDependsOnPanel.setVisible(b);
+    myConditionsPanel.setVisible(b);
+    if (b) {
+      myActionsPanel.setVisible(true);
+    }
+    if (!b) {
+      myPanel.setPreferredSize(new Dimension(500, -1));
+    }
+  }
+
+  public void setDelegate(Delegate delegate) {
+    myDelegate = delegate;
+  }
+
+  private class MyTextField extends JTextField {
+    public MyTextField() {
+    }
+
+    public String getToolTipText(MouseEvent event) {
+      reloadClassFilters();
+      updateClassFilterEditor(false);
+      reloadInstanceFilters();
+      updateInstanceFilterEditor(false);
+      String toolTipText = super.getToolTipText(event);
+      return getToolTipText().length() == 0 ? null : toolTipText;
+    }
+
+    public JToolTip createToolTip() {
+      JToolTip toolTip = new JToolTip(){{
+        setUI(new MultiLineTooltipUI());
+      }};
+      toolTip.setComponent(this);
+      return toolTip;
+    }
+  }
+
+  private static void insert(JPanel panel, JComponent component) {
+    panel.setLayout(new BorderLayout());
+    panel.add(component, BorderLayout.CENTER);
+  }
+
+  public BreakpointPropertiesPanel(final Project project, final Key<? extends Breakpoint> breakpointCategory, boolean compact) {
+    myProject = project;
+    myBreakpointCategory = breakpointCategory;
+    myCompact = compact;
+
+    mySuspendPolicyGroup = new ButtonGroup();
+    mySuspendPolicyGroup.add(myRbSuspendAll);
+    mySuspendPolicyGroup.add(myRbSuspendThread);
+
+    updateSuspendPolicyRbFont();
+    final ItemListener suspendPolicyChangeListener = new ItemListener() {
+      public void itemStateChanged(final ItemEvent e) {
+        final BreakpointDefaults defaults = getBreakpointManager(myProject).getBreakpointDefaults(breakpointCategory);
+        myMakeDefaultButton.setEnabled(!defaults.getSuspendPolicy().equals(getSelectedSuspendPolicy()) || defaults.isConditionEnabled() != myConditionCheckbox.isSelected());
+      }
+    };
+
+    myCbSuspend.addActionListener(new ActionListener() {
+      @Override
+      public void actionPerformed(ActionEvent event) {
+        final boolean enabled = myCbSuspend.isSelected();
+        myRbSuspendAll.setEnabled(enabled);
+        myRbSuspendThread.setEnabled(enabled);
+      }
+    });
+
+
+    myRbSuspendAll.addItemListener(suspendPolicyChangeListener);
+    myRbSuspendThread.addItemListener(suspendPolicyChangeListener);
+    myConditionCheckbox.addItemListener(suspendPolicyChangeListener);
+
+    myMakeDefaultButton.addActionListener(new ActionListener() {
+      public void actionPerformed(final ActionEvent e) {
+        final BreakpointManager breakpointManager = getBreakpointManager(myProject);
+        final String suspendPolicy = getSelectedSuspendPolicy();
+        breakpointManager.setBreakpointDefaults(breakpointCategory, new BreakpointDefaults(suspendPolicy, myConditionCheckbox.isSelected()));
+        updateSuspendPolicyRbFont();
+        if (DebuggerSettings.SUSPEND_THREAD.equals(suspendPolicy)) {
+          myRbSuspendThread.requestFocus();
+        }
+        else {
+          myRbSuspendAll.requestFocus();
+        }
+        myMakeDefaultButton.setEnabled(false);
+      }
+    });
+
+    myConditionCombo = new DebuggerExpressionComboBox(project, "LineBreakpoint condition");
+    myConditionCombo.addDocumentListener(new DocumentListener() {
+      @Override
+      public void beforeDocumentChange(DocumentEvent event) {
+        myConditionCheckbox.setSelected(true);
+      }
+
+      @Override
+      public void documentChanged(DocumentEvent event) {
+
+      }
+    });
+
+    myConditionCombo.getEditorComponent().addMouseListener(new MouseAdapter() {
+      @Override
+      public void mouseClicked(MouseEvent event) {
+        myConditionCombo.setEnabled(true);
+        myConditionCheckbox.setSelected(true);
+      }
+    });
+
+    if (myCompact) {
+      myPanel.addFocusListener(new FocusAdapter() {
+        @Override
+        public void focusGained(FocusEvent event) {
+          IdeFocusManager.findInstance().requestFocus(myConditionCombo, true);
+        }
+      });
+    }
+
+    myLogExpressionCombo = new DebuggerExpressionComboBox(project, "LineBreakpoint logMessage");
+
+    myInstanceFiltersField = new FieldPanel(new MyTextField(), "", null,
+     new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        reloadInstanceFilters();
+        EditInstanceFiltersDialog _dialog = new EditInstanceFiltersDialog(myProject);
+        _dialog.setFilters(myInstanceFilters);
+        _dialog.show();
+        if(_dialog.getExitCode() == DialogWrapper.OK_EXIT_CODE) {
+          myInstanceFilters = _dialog.getFilters();
+          updateInstanceFilterEditor(true);
+        }
+      }
+    },
+     null
+    );
+
+    myClassFiltersField = new FieldPanel(new MyTextField(), "", null,
+     new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        reloadClassFilters();
+
+        ClassFilter classFilter = createClassConditionFilter();
+
+        EditClassFiltersDialog _dialog = new EditClassFiltersDialog(myProject, classFilter);
+        _dialog.setFilters(myClassFilters, myClassExclusionFilters);
+        _dialog.show();
+        if (_dialog.getExitCode() == DialogWrapper.OK_EXIT_CODE) {
+          myClassFilters = _dialog.getFilters();
+          myClassExclusionFilters = _dialog.getExclusionFilters();
+          updateClassFilterEditor(true);
+        }
+      }
+    },
+     null
+    );
+    ToolTipManager.sharedInstance().registerComponent(myClassFiltersField.getTextField());
+    ToolTipManager.sharedInstance().registerComponent(myInstanceFiltersField.getTextField());
+
+    JComponent specialBox = createSpecialBox();
+    if(specialBox != null) {
+      insert(mySpecialBoxPanel, specialBox);
+    } 
+    else {
+      mySpecialBoxPanel.setVisible(false);
+    }
+
+    final JPanel conditionPanel = new JPanel(new BorderLayout());
+    conditionPanel.add(myConditionCombo, BorderLayout.CENTER);
+    myConditionMagnifierButton = new FixedSizeButton(myConditionCombo);
+    conditionPanel.add(myConditionMagnifierButton, BorderLayout.EAST);
+    myConditionMagnifierButton.setFocusable(false);
+    myConditionMagnifierButton.addActionListener(new MagnifierButtonAction(project, myConditionCombo, "Condition"));
+
+    insert(myConditionComboPanel, conditionPanel);
+    insert(myLogExpressionComboPanel, myLogExpressionCombo);
+
+    insert(myInstanceFiltersFieldPanel, myInstanceFiltersField);
+    insert(myClassFiltersFieldPanel, myClassFiltersField);
+
+    DebuggerUIUtil.enableEditorOnCheck(myLogExpressionCheckBox, myLogExpressionCombo);
+    ActionListener updateListener = new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        updateCheckboxes();
+      }
+    };
+    myPassCountCheckbox.addActionListener(updateListener);
+    myInstanceFiltersCheckBox.addActionListener(updateListener);
+    myClassFiltersCheckBox.addActionListener(updateListener);
+    myConditionCheckbox.addActionListener(updateListener);
+    DebuggerUIUtil.focusEditorOnCheck(myPassCountCheckbox, myPassCountField);
+    DebuggerUIUtil.focusEditorOnCheck(myLogExpressionCheckBox, myLogExpressionCombo);
+    DebuggerUIUtil.focusEditorOnCheck(myInstanceFiltersCheckBox, myInstanceFiltersField.getTextField());
+    DebuggerUIUtil.focusEditorOnCheck(myClassFiltersCheckBox, myClassFiltersField.getTextField());
+    DebuggerUIUtil.focusEditorOnCheck(myConditionCheckbox, myConditionCombo);
+
+    IJSwingUtilities.adjustComponentsOnMac(myCbSuspend);
+    IJSwingUtilities.adjustComponentsOnMac(myLogExpressionCheckBox);
+    IJSwingUtilities.adjustComponentsOnMac(myLogMessageCheckBox);
+  }
+
+  private List<BreakpointItem> getBreakpointItemsExceptMy() {
+    List<BreakpointItem> items = new ArrayList<BreakpointItem>();
+    final DebuggerSupport support = DebuggerSupport.getDebuggerSupport(JavaDebuggerSupport.class);
+    support.getBreakpointPanelProvider().provideBreakpointItems(myProject, items);
+    for (BreakpointItem item : items) {
+      if (item.getBreakpoint() == myBreakpoint) {
+        items.remove(item);
+        break;
+      }
+    }
+    items.add(new BreakpointNoneItem());
+    return items;
+  }
+
+  private void saveMasterBreakpoint() {
+    Breakpoint masterBreakpoint = (Breakpoint)myMasterBreakpointChooser.getSelectedBreakpoint();
+    if (masterBreakpoint == null) {
+      getBreakpointManager(myProject).removeBreakpointRule(myBreakpoint);
+    }
+    else {
+      EnableBreakpointRule rule = findMasterBreakpointRule();
+      boolean selected = myLeaveEnabledRadioButton.isSelected();
+      if (rule != null) {
+        if (rule.getMasterBreakpoint() != masterBreakpoint || rule.isLeaveEnabled() != selected) {
+          getBreakpointManager(myProject).removeBreakpointRule(rule);
+        }
+        else {
+          return;
+        }
+      }
+      getBreakpointManager(myProject).addBreakpointRule(new EnableBreakpointRule(getBreakpointManager(myProject), masterBreakpoint, myBreakpoint, selected));
+    }
+  }
+
+  private String getSelectedSuspendPolicy() {
+    if (myRbSuspendThread.isSelected()) {
+      return DebuggerSettings.SUSPEND_THREAD;
+    }
+    return DebuggerSettings.SUSPEND_ALL;
+  }
+
+  private void updateSuspendPolicyRbFont() {
+    final String defPolicy = getBreakpointManager(myProject).getBreakpointDefaults(myBreakpointCategory).getSuspendPolicy();
+    
+    final Font font = myRbSuspendAll.getFont().deriveFont(Font.PLAIN);
+    final Font boldFont = font.deriveFont(Font.BOLD);
+    
+    myRbSuspendAll.setFont(DebuggerSettings.SUSPEND_ALL.equals(defPolicy)? boldFont : font);
+    myRbSuspendThread.setFont(DebuggerSettings.SUSPEND_THREAD.equals(defPolicy)? boldFont : font);
+  }
+
+  protected ClassFilter createClassConditionFilter() {
+    ClassFilter classFilter;
+    if(myBreakpointPsiClass != null) {
+      classFilter = new ClassFilter() {
+        public boolean isAccepted(PsiClass aClass) {
+          return myBreakpointPsiClass == aClass || aClass.isInheritor(myBreakpointPsiClass, true);
+        }
+      };
+    }
+    else {
+      classFilter = null;
+    }
+    return classFilter;
+  }
+
+  protected JComponent createSpecialBox() {
+    return null;
+  }
+
+  /**
+   * Init UI components with the values from Breakpoint
+   */
+  public void initFrom(Breakpoint breakpoint, boolean moreOptionsVisible1) {
+    myBreakpoint = breakpoint;
+    boolean moreOptionsVisible = moreOptionsVisible1;
+    boolean actionsPanelVisible = moreOptionsVisible1;
+
+    initMasterBreakpointPanel();
+
+    if (breakpoint.COUNT_FILTER > 0) {
+      myPassCountField.setText(Integer.toString(breakpoint.COUNT_FILTER));
+      moreOptionsVisible = true;
+    }
+    else {
+      myPassCountField.setText("");
+    }
+
+    PsiElement context = breakpoint.getEvaluationElement();
+    myPassCountCheckbox.setSelected(breakpoint.COUNT_FILTER_ENABLED);
+
+    myConditionCheckbox.setSelected(breakpoint.CONDITION_ENABLED);
+
+    myConditionCombo.setEnabled(breakpoint.CONDITION_ENABLED);
+
+    myConditionCombo.setContext(context);
+    myConditionCombo.setText(breakpoint.getCondition() != null ? breakpoint.getCondition() : emptyText());
+
+    myCbSuspend.setSelected(breakpoint.SUSPEND);
+    myRbSuspendThread.setEnabled(myCbSuspend.isSelected());
+    myRbSuspendAll.setEnabled(myCbSuspend.isSelected());
+
+    if(!breakpoint.SUSPEND) {
+      actionsPanelVisible = true;
+    }
+    if(DebuggerSettings.SUSPEND_THREAD.equals(breakpoint.SUSPEND_POLICY)){
+      myRbSuspendThread.setSelected(true);
+    }
+    else {
+      myRbSuspendAll.setSelected(true);
+    }
+
+    myCbSuspend.addActionListener(new ActionListener() {
+      @Override
+      public void actionPerformed(ActionEvent event) {
+        if (!myActionsPanel.isVisible()) {
+          if (!myCbSuspend.isSelected()) {
+            if (myDelegate != null) {
+              myDelegate.showActionsPanel();
+            }
+          }
+        }
+        myRbSuspendThread.setEnabled(myCbSuspend.isSelected());
+        myRbSuspendAll.setEnabled(myCbSuspend.isSelected());
+      }
+    });
+    myLogMessageCheckBox.setSelected(breakpoint.LOG_ENABLED);
+    myLogExpressionCheckBox.setSelected(breakpoint.LOG_EXPRESSION_ENABLED);
+    if (breakpoint.LOG_ENABLED || breakpoint.LOG_EXPRESSION_ENABLED) {
+      actionsPanelVisible = true;
+    }
+
+    myLogExpressionCombo.setContext(context);
+
+    if (breakpoint.getLogMessage() != null) {
+      myLogExpressionCombo.setText(breakpoint.getLogMessage());
+    }
+    else {
+      myLogExpressionCombo.setText(emptyText());
+    }
+
+    myLogExpressionCombo.setEnabled(breakpoint.LOG_EXPRESSION_ENABLED);
+    if (breakpoint.LOG_EXPRESSION_ENABLED) {
+      actionsPanelVisible = true;
+    }
+
+    myInstanceFiltersCheckBox.setSelected(breakpoint.INSTANCE_FILTERS_ENABLED);
+    myInstanceFiltersField.setEnabled(breakpoint.INSTANCE_FILTERS_ENABLED);
+    myInstanceFiltersField.getTextField().setEditable(breakpoint.INSTANCE_FILTERS_ENABLED);
+    myInstanceFilters = breakpoint.getInstanceFilters();
+    updateInstanceFilterEditor(true);
+    if (breakpoint.INSTANCE_FILTERS_ENABLED) {
+      moreOptionsVisible = true;
+    }
+
+    myClassFiltersCheckBox.setSelected(breakpoint.CLASS_FILTERS_ENABLED);
+    myClassFiltersField.setEnabled(breakpoint.CLASS_FILTERS_ENABLED);
+    myClassFiltersField.getTextField().setEditable(breakpoint.CLASS_FILTERS_ENABLED);
+    myClassFilters = breakpoint.getClassFilters();
+    myClassExclusionFilters = breakpoint.getClassExclusionFilters();
+    updateClassFilterEditor(true);
+    if (breakpoint.CLASS_FILTERS_ENABLED) {
+      moreOptionsVisible = true;
+    }
+
+    myBreakpointPsiClass = breakpoint.getPsiClass();
+
+    updateCheckboxes();
+
+    setActionsPanelVisible(actionsPanelVisible && !moreOptionsVisible1);
+    setMoreOptionsVisible(moreOptionsVisible);
+  }
+
+  private void initMasterBreakpointPanel() {
+    final EnableBreakpointRule rule = findMasterBreakpointRule();
+
+    final Breakpoint baseBreakpoint = rule != null ? rule.getMasterBreakpoint() : null;
+    updateMasterBreakpointPanel(rule);
+
+
+    myMasterBreakpointChooser = new BreakpointChooser(myProject, new BreakpointChooser.Delegate() {
+      @Override
+      public void breakpointChosen(Project project, BreakpointItem item) {
+        final boolean enabled = item != null && item.getBreakpoint() != null;
+        myLeaveEnabledRadioButton.setEnabled(enabled);
+        myDisableAgainRadio.setEnabled(enabled);
+        myEnableOrDisableLabel.setEnabled(enabled);
+
+        if (item != null) {
+
+          saveMasterBreakpoint();
+        }
+
+        updateMasterBreakpointPanel(findMasterBreakpointRule());
+
+      }
+    }, baseBreakpoint, getBreakpointItemsExceptMy());
+
+    insert(myDependentBreakpointComboPanel, myMasterBreakpointChooser.getComponent());
+
+  }
+
+  private @Nullable EnableBreakpointRule findMasterBreakpointRule() {
+    return myBreakpoint != null? getBreakpointManager(myProject).findBreakpointRule(myBreakpoint) : null;
+  }
+
+  private void updateMasterBreakpointPanel(@Nullable EnableBreakpointRule rule) {
+    final boolean leaveEnabled = rule != null && rule.isLeaveEnabled();
+    if (leaveEnabled) {
+      myLeaveEnabledRadioButton.setSelected(true);
+    }
+    else {
+      myDisableAgainRadio.setSelected(true);
+    }
+  }
+
+  private TextWithImportsImpl emptyText() {
+    return new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, "");
+  }
+
+  /**
+   * Save values in the UI components to the breakpoint object
+   */
+  public void saveTo(Breakpoint breakpoint, @NotNull Runnable afterUpdate) {
+
+    saveMasterBreakpoint();
+    try {
+      String text = myPassCountField.getText().trim();
+      int count = !"".equals(text)? Integer.parseInt(text) : 0;
+      breakpoint.COUNT_FILTER = count;
+      if (breakpoint.COUNT_FILTER < 0) {
+        breakpoint.COUNT_FILTER = 0;
+      }
+    }
+    catch (Exception e) {
+    }
+    breakpoint.COUNT_FILTER_ENABLED = breakpoint.COUNT_FILTER > 0 && myPassCountCheckbox.isSelected();
+    breakpoint.setCondition(myConditionCombo.getText());
+    breakpoint.CONDITION_ENABLED = myConditionCheckbox.isSelected();
+    breakpoint.setLogMessage(myLogExpressionCombo.getText());
+    breakpoint.LOG_EXPRESSION_ENABLED = !breakpoint.getLogMessage().isEmpty() && myLogExpressionCheckBox.isSelected();
+    breakpoint.LOG_ENABLED = myLogMessageCheckBox.isSelected();
+    breakpoint.SUSPEND = myCbSuspend.isSelected();
+    breakpoint.SUSPEND_POLICY = getSelectedSuspendPolicy();
+    reloadInstanceFilters();
+    reloadClassFilters();
+    updateInstanceFilterEditor(true);
+    updateClassFilterEditor(true);
+
+    breakpoint.INSTANCE_FILTERS_ENABLED = myInstanceFiltersField.getText().length() > 0 && myInstanceFiltersCheckBox.isSelected();
+    breakpoint.CLASS_FILTERS_ENABLED = myClassFiltersField.getText().length() > 0 && myClassFiltersCheckBox.isSelected();
+    breakpoint.setClassFilters(myClassFilters);
+    breakpoint.setClassExclusionFilters(myClassExclusionFilters);
+    breakpoint.setInstanceFilters(myInstanceFilters);
+
+    myConditionCombo.addRecent(myConditionCombo.getText());
+    myLogExpressionCombo.addRecent(myLogExpressionCombo.getText());
+    breakpoint.updateUI(afterUpdate);
+  }
+
+  private static String concatWithEx(List<String> s, String concator, int N, String NthConcator) {
+    String result = "";
+    int i = 1;
+    for (Iterator iterator = s.iterator(); iterator.hasNext(); i++) {
+      String str = (String) iterator.next();
+      result += str;
+      if(iterator.hasNext()){
+        if(i % N == 0){
+          result += NthConcator;
+        }
+        else {
+          result += concator;
+        }
+      }
+    }
+    return result;
+  }
+
+  private void updateInstanceFilterEditor(boolean updateText) {
+    List<String> filters = new ArrayList<String>();
+    for (InstanceFilter instanceFilter : myInstanceFilters) {
+      if (instanceFilter.isEnabled()) {
+        filters.add(Long.toString(instanceFilter.getId()));
+      }
+    }
+    if (updateText) {
+      myInstanceFiltersField.setText(StringUtil.join(filters, " "));
+    }
+
+    String tipText = concatWithEx(filters, " ", (int)Math.sqrt(myInstanceFilters.length) + 1, "\n");
+    myInstanceFiltersField.getTextField().setToolTipText(tipText);
+  }
+
+  private void reloadInstanceFilters() {
+    String filtersText = myInstanceFiltersField.getText();
+
+    ArrayList<InstanceFilter> idxs = new ArrayList<InstanceFilter>();
+    int startNumber = -1;
+    for(int i = 0; i <= filtersText.length(); i++) {
+      if(i < filtersText.length() && Character.isDigit(filtersText.charAt(i))) {
+        if(startNumber == -1) {
+          startNumber = i;
+        }
+      }
+      else {
+        if(startNumber >=0) {
+          idxs.add(InstanceFilter.create(filtersText.substring(startNumber, i)));
+          startNumber = -1;
+        }
+      }
+    }
+    for (InstanceFilter instanceFilter : myInstanceFilters) {
+      if (!instanceFilter.isEnabled()) {
+        idxs.add(instanceFilter);
+      }
+    }
+    myInstanceFilters = idxs.toArray(new InstanceFilter[idxs.size()]);
+  }
+
+  private void updateClassFilterEditor(boolean updateText) {
+    List<String> filters = new ArrayList<String>();
+    for (com.intellij.ui.classFilter.ClassFilter classFilter : myClassFilters) {
+      if (classFilter.isEnabled()) {
+        filters.add(classFilter.getPattern());
+      }
+    }
+    List<String> excludeFilters = new ArrayList<String>();
+    for (com.intellij.ui.classFilter.ClassFilter classFilter : myClassExclusionFilters) {
+      if (classFilter.isEnabled()) {
+        excludeFilters.add("-" + classFilter.getPattern());
+      }
+    }
+    if (updateText) {
+      String editorText = StringUtil.join(filters, " ");
+      if(!filters.isEmpty()) {
+        editorText += " ";
+      }
+      editorText += StringUtil.join(excludeFilters, " ");
+      myClassFiltersField.setText(editorText);
+    }
+
+    int width = (int)Math.sqrt(myClassExclusionFilters.length + myClassFilters.length) + 1;
+    String tipText = concatWithEx(filters, " ", width, "\n");
+    if(!filters.isEmpty()) {
+      tipText += "\n";
+    }
+    tipText += concatWithEx(excludeFilters, " ", width, "\n");
+    myClassFiltersField.getTextField().setToolTipText(tipText);
+  }
+
+  private void reloadClassFilters() {
+    String filtersText = myClassFiltersField.getText();
+
+    ArrayList<com.intellij.ui.classFilter.ClassFilter> classFilters     = new ArrayList<com.intellij.ui.classFilter.ClassFilter>();
+    ArrayList<com.intellij.ui.classFilter.ClassFilter> exclusionFilters = new ArrayList<com.intellij.ui.classFilter.ClassFilter>();
+    int startFilter = -1;
+    for(int i = 0; i <= filtersText.length(); i++) {
+      if(i < filtersText.length() && !Character.isWhitespace(filtersText.charAt(i))){
+        if(startFilter == -1) {
+          startFilter = i;
+        }
+      }
+      else {
+        if(startFilter >=0) {
+          if(filtersText.charAt(startFilter) == '-') {
+            exclusionFilters.add(new com.intellij.ui.classFilter.ClassFilter(filtersText.substring(startFilter + 1, i)));
+          }
+          else {
+            classFilters.add(new com.intellij.ui.classFilter.ClassFilter(filtersText.substring(startFilter, i)));
+          }
+          startFilter = -1;
+        }
+      }
+    }
+    for (com.intellij.ui.classFilter.ClassFilter classFilter : myClassFilters) {
+      if (!classFilter.isEnabled()) {
+        classFilters.add(classFilter);
+      }
+    }
+    for (com.intellij.ui.classFilter.ClassFilter classFilter : myClassExclusionFilters) {
+      if (!classFilter.isEnabled()) {
+        exclusionFilters.add(classFilter);
+      }
+    }
+    myClassFilters          = classFilters    .toArray(new com.intellij.ui.classFilter.ClassFilter[classFilters    .size()]);
+    myClassExclusionFilters = exclusionFilters.toArray(new com.intellij.ui.classFilter.ClassFilter[exclusionFilters.size()]);
+  }
+
+  public void setEnabled(boolean enabled) {
+    myPanel.setEnabled(enabled);
+    Component[] components = myPanel.getComponents();
+    for (Component component : components) {
+      component.setEnabled(enabled);
+    }
+  }
+
+  protected void updateCheckboxes() {
+    JCheckBox [] checkBoxes = {myConditionCheckbox, myInstanceFiltersCheckBox, myClassFiltersCheckBox };
+    boolean passCountApplicable = true;
+    for (JCheckBox checkBox : checkBoxes) {
+      if (checkBox.isSelected()) {
+        passCountApplicable = false;
+        break;
+      }
+    }
+    myPassCountCheckbox.setEnabled(passCountApplicable);
+
+    final boolean passCountSelected = myPassCountCheckbox.isSelected();
+    for (JCheckBox checkBox : checkBoxes) {
+      checkBox.setEnabled(!passCountSelected);
+    }
+
+    myPassCountField.setEditable(myPassCountCheckbox.isSelected());
+    myPassCountField.setEnabled (myPassCountCheckbox.isSelected());
+
+    myConditionCombo.setEnabled(myConditionCheckbox.isSelected());
+    myConditionMagnifierButton.setEnabled(myConditionCheckbox.isSelected());
+
+    myInstanceFiltersField.setEnabled(myInstanceFiltersCheckBox.isSelected());
+    myInstanceFiltersField.getTextField().setEditable(myInstanceFiltersCheckBox.isSelected());
+
+    myClassFiltersField.setEnabled(myClassFiltersCheckBox.isSelected());
+    myClassFiltersField.getTextField().setEditable(myClassFiltersCheckBox.isSelected());
+  }
+
+  public JPanel getPanel() {
+    return myPanel;
+  }
+
+  private static BreakpointManager getBreakpointManager(Project project) {
+    return DebuggerManagerEx.getInstanceEx(project).getBreakpointManager();
+  }
+
+  private static class MagnifierButtonAction implements ActionListener {
+    private final Project myProject;
+    private final CompletionEditor myTargetEditor;
+    private final String myDialogTitle;
+    private DebuggerStatementEditor myEditor;
+
+    private MagnifierButtonAction(final Project project, final CompletionEditor targetEditor, final String dialogTitle) {
+      myProject = project;
+      myTargetEditor = targetEditor;
+      myDialogTitle = dialogTitle;
+    }
+
+    public void actionPerformed(final ActionEvent e) {
+      new DialogWrapper(myTargetEditor, true){
+        public void show() {
+          setTitle(myDialogTitle);
+          setModal(true);
+          init();
+          super.show();
+        }
+
+        public JComponent getPreferredFocusedComponent() {
+          return myEditor;
+        }
+
+        @Nullable
+        protected JComponent createCenterPanel() {
+          final JPanel panel = new JPanel(new BorderLayout());
+          myEditor = new DebuggerStatementEditor(myProject, myTargetEditor.getContext(), myTargetEditor.getRecentsId(), DefaultCodeFragmentFactory.getInstance());
+          myEditor.setPreferredSize(new Dimension(400, 150));
+          myEditor.setText(myTargetEditor.getText());
+          panel.add(myEditor, BorderLayout.CENTER);
+          return panel;
+        }
+
+        protected void doOKAction() {
+          myTargetEditor.setText(myEditor.getText());
+          super.doOKAction();
+        }
+      }.show();
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointTable.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointTable.java
new file mode 100644
index 0000000..7530fa5
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointTable.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.breakpoints;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.util.ui.Table;
+import com.intellij.xdebugger.XDebuggerBundle;
+
+import javax.swing.*;
+import javax.swing.table.DefaultTableCellRenderer;
+import javax.swing.table.TableCellRenderer;
+import javax.swing.table.TableColumn;
+import javax.swing.table.TableColumnModel;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: May 23, 2005
+ */
+public class BreakpointTable extends Table {
+  public BreakpointTable(final Project project) {
+    super(new BreakpointTableModel(project));
+    setColumnSelectionAllowed(false);
+    InputMap inputMap = getInputMap();
+    ActionMap actionMap = getActionMap();
+    Object o = inputMap.get(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0));
+    if (o == null) {
+      //noinspection HardCodedStringLiteral
+      o = "enable_disable";
+      inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), o);
+    }
+    actionMap.put(o, new AbstractAction() {
+      public void actionPerformed(ActionEvent e) {
+        if (isEditing()) {
+          return;
+        }
+        int[] indices = getSelectedRows();
+        boolean currentlyMarked = true;
+        for (int i = 0; i < indices.length; i++) {
+          final Boolean isMarked = (Boolean)getValueAt(indices[i], BreakpointTableModel.ENABLED_STATE);
+          currentlyMarked = isMarked != null? isMarked.booleanValue() : false;
+          if (!currentlyMarked) {
+            break;
+          }
+        }
+        final Boolean valueToSet = currentlyMarked ? Boolean.FALSE : Boolean.TRUE;
+        for (int i = 0; i < indices.length; i++) {
+          setValueAt(valueToSet, indices[i], BreakpointTableModel.ENABLED_STATE);
+        }
+      }
+    });
+
+    setShowGrid(false);
+    setIntercellSpacing(new Dimension(0, 0));
+    setTableHeader(null);
+    setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
+    setColumnSelectionAllowed(false);
+
+    int width = new JCheckBox().getPreferredSize().width;
+    TableColumnModel columnModel = getColumnModel();
+
+    TableColumn enabledStateColumn = columnModel.getColumn(BreakpointTableModel.ENABLED_STATE);
+    enabledStateColumn.setPreferredWidth(width);
+    enabledStateColumn.setMaxWidth(width);
+    final Class enabledStateColumnClass = getModel().getColumnClass(BreakpointTableModel.ENABLED_STATE);
+    final TableCellRenderer delegateRenderer = getDefaultRenderer(enabledStateColumnClass);
+    setDefaultRenderer(enabledStateColumnClass, new DefaultTableCellRenderer() {
+      public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+        final Component component = delegateRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
+        if (component instanceof JComponent) {
+          ((JComponent)component).setBorder(null);
+        }
+        return component;
+      }
+    });
+    columnModel.getColumn(BreakpointTableModel.NAME).setCellRenderer(new BreakpointNameCellRenderer());
+
+    getEmptyText().setText(XDebuggerBundle.message("debugger.no.breakpoints"));
+  }
+
+  public BreakpointTableModel getModel() {
+    return (BreakpointTableModel)super.getModel();
+  }
+  
+  public void setBreakpoints(Breakpoint[] breakpoints) {
+    getModel().setBreakpoints(breakpoints);
+  }
+
+  public final java.util.List<Breakpoint> getBreakpoints() {
+    return getModel().getBreakpoints();
+  }
+
+  public Breakpoint[] getSelectedBreakpoints() {
+    if (getRowCount() == 0) {
+      return Breakpoint.EMPTY_ARRAY;
+    }
+
+    int[] rows = getSelectedRows();
+    if (rows.length == 0) {
+      return Breakpoint.EMPTY_ARRAY;
+    }
+    Breakpoint[] rv = new Breakpoint[rows.length];
+    for (int idx = 0; idx < rows.length; idx++) {
+      rv[idx] = getModel().getBreakpoint(rows[idx]);
+    }
+    return rv;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointTableModel.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointTableModel.java
new file mode 100644
index 0000000..6999260
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointTableModel.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class BreakpointTableModel
+ * @author Jeka
+ */
+package com.intellij.debugger.ui.breakpoints;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.openapi.project.Project;
+import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.ui.ItemRemovable;
+
+import javax.swing.table.AbstractTableModel;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public class BreakpointTableModel extends AbstractTableModel implements ItemRemovable {
+  public static final int ENABLED_STATE = 0;
+  public static final int NAME = 1;
+
+  private java.util.List<Breakpoint> myBreakpoints = null;
+  private final BreakpointManager myBreakpointManager;
+
+  public BreakpointTableModel(final Project project) {
+    myBreakpoints = new ArrayList<Breakpoint>();
+    myBreakpointManager = DebuggerManagerEx.getInstanceEx(project).getBreakpointManager();
+  }
+
+  public final void setBreakpoints(Breakpoint[] breakpoints) {
+    myBreakpoints.clear();
+    if (breakpoints != null) {
+      ContainerUtil.addAll(myBreakpoints, breakpoints);
+    }
+    fireTableDataChanged();
+  }
+
+  public List<Breakpoint> getBreakpoints() {
+    return Collections.unmodifiableList(myBreakpoints);
+  }
+
+  public void removeBreakpoints(Breakpoint[] breakpoints) {
+    myBreakpoints.removeAll(Arrays.asList(breakpoints));
+    fireTableDataChanged();
+  }
+
+  public Breakpoint getBreakpoint(int index) {
+    if (index < 0 || index >= myBreakpoints.size()) return null;
+    return myBreakpoints.get(index);
+  }
+
+  public boolean isBreakpointEnabled(int index) {
+    return ((Boolean)getValueAt(index, ENABLED_STATE)).booleanValue();
+  }
+
+  public int getBreakpointIndex(Breakpoint breakpoint) {
+    return myBreakpoints.indexOf(breakpoint);
+  }
+
+  public void insertBreakpointAt(Breakpoint breakpoint, int index) {
+    myBreakpoints.add(index, breakpoint);
+    fireTableRowsInserted(index, index);
+  }
+
+  public void addBreakpoint(Breakpoint breakpoint) {
+    myBreakpoints.add(breakpoint);
+    int row = myBreakpoints.size() - 1;
+    fireTableRowsInserted(row, row);
+  }
+
+  public void removeRow(int idx) {
+    if (idx >= 0 && idx < myBreakpoints.size()) {
+      myBreakpoints.remove(idx);
+      fireTableRowsDeleted(idx, idx);
+    }
+  }
+
+  public int getRowCount() {
+    return myBreakpoints.size();
+  }
+
+  public int getColumnCount() {
+    return 2;
+  }
+
+  public String getColumnName(int column) {
+    switch (column) {
+    case ENABLED_STATE:
+      return DebuggerBundle.message("breakpoint.table.header.column.enabled");
+    case NAME:
+      return DebuggerBundle.message("breakpoint.table.header.column.name");
+    default           :
+      return "";
+    }
+  }
+
+  public Object getValueAt(int rowIndex, int columnIndex) {
+    Breakpoint breakpoint = myBreakpoints.get(rowIndex);
+    if (columnIndex == NAME) {
+      return breakpoint.getDisplayName();
+    }
+    if (columnIndex == ENABLED_STATE) {
+      return breakpoint.ENABLED? Boolean.TRUE : Boolean.FALSE;
+    }
+    return null;
+  }
+
+  public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
+    if (rowIndex < 0 || rowIndex >= myBreakpoints.size()) {
+      return;
+    }
+    Breakpoint breakpoint = myBreakpoints.get(rowIndex);
+/*
+    if (columnIndex == NAME) {
+      breakpoint.setDisplayName((aValue != null)? aValue.toString() : "");
+    }
+    else
+*/
+    if (columnIndex == ENABLED_STATE) {
+      final boolean isEnabled = aValue == null || ((Boolean)aValue).booleanValue();
+      final boolean valueChanged = isEnabled != breakpoint.ENABLED;
+      breakpoint.ENABLED = isEnabled;
+      if (valueChanged) {
+        breakpoint.updateUI();
+      }
+    }
+    fireTableRowsUpdated(rowIndex, rowIndex);
+  }
+
+  public Class getColumnClass(int columnIndex) {
+    if (columnIndex == ENABLED_STATE) {
+      return Boolean.class;
+    }
+    return super.getColumnClass(columnIndex);
+  }
+
+  public boolean isCellEditable(int rowIndex, int columnIndex) {
+    if (columnIndex != ENABLED_STATE) {
+      return false;
+    }
+    final boolean isSlave = myBreakpointManager.findMasterBreakpoint(myBreakpoints.get(rowIndex)) != null;
+    return !isSlave;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointTree.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointTree.java
new file mode 100644
index 0000000..2d39fe0
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointTree.java
@@ -0,0 +1,821 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.breakpoints;
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.openapi.project.Project;
+import com.intellij.ui.*;
+import com.intellij.util.ArrayUtil;
+import com.intellij.util.PlatformIcons;
+import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.containers.Convertor;
+import com.intellij.util.ui.tree.TreeUtil;
+import com.intellij.xdebugger.XDebuggerBundle;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.TreePath;
+import java.util.*;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: May 20, 2005
+ */
+public class BreakpointTree extends CheckboxTree {
+  private static final String DEFAULT_PACKAGE_NAME = DebuggerBundle.message("default.package.name");
+  private final CheckedTreeNode myRootNode;
+  private final List<Breakpoint> myBreakpoints = new ArrayList<Breakpoint>();
+  private final Map<TreeDescriptor, CheckedTreeNode> myDescriptorToNodeMap = new HashMap<TreeDescriptor, CheckedTreeNode>();
+  
+  private boolean myGroupByMethods = false;
+  private boolean myGroupByClasses = true;
+  private boolean myFlattenPackages = true;
+  
+  private final NodeAppender[] myAppenders = {
+    new BreakpointToMethodAppender(),
+    new BreakpointToClassAppender(),
+    new BreakpointToPackageAppender(),
+    new MethodToClassAppender(),
+    new MethodToPackageAppender(),
+    new ClassToPackageAppender(),
+    new PackageToPackageAppender(),
+  };
+
+  private final Comparator<CheckedTreeNode> myNodeComparator = new Comparator<CheckedTreeNode>() {
+    public int compare(CheckedTreeNode o1, CheckedTreeNode o2) {
+      final int w1 = getWeight(o1);
+      final int w2 = getWeight(o2);
+      if (w1 != w2) {
+        return w1 - w2;
+      }
+      final TreeDescriptor d1 = (TreeDescriptor)o1.getUserObject();
+      final TreeDescriptor d2 = (TreeDescriptor)o2.getUserObject();
+      if (d1 instanceof BreakpointDescriptor && d2 instanceof BreakpointDescriptor) {
+        return 0;
+      }
+      return d1.getDisplayString().compareTo(d2.getDisplayString());
+    }
+
+    private int getWeight(CheckedTreeNode node) {
+      if (node.getUserObject() instanceof BreakpointDescriptor) {
+        return 100;
+      }
+      if (node.getUserObject() instanceof MethodDescriptor) {
+        return 90;
+      }
+      if (node.getUserObject() instanceof PackageDescriptor) {
+        return 80;
+      }
+      if (node.getUserObject() instanceof ClassDescriptor) {
+        return 70;
+      }
+      return 50;
+    }
+  };
+  private final BreakpointManager myBreakpointManager;
+  private final BreakpointManagerListener myNodeUpdateListener;
+
+  protected void installSpeedSearch() {
+    new TreeSpeedSearch(this, new Convertor<TreePath, String>() {
+      public String convert(TreePath path) {
+        final CheckedTreeNode node = (CheckedTreeNode)path.getLastPathComponent();
+        return ((TreeDescriptor)node.getUserObject()).getDisplayString();
+      }
+    });
+  }
+
+  public boolean getExpandsSelectedPaths() {
+    return true;
+  }
+
+  public Breakpoint[] getSelectedBreakpoints() {
+    final TreePath[] selectionPaths = getSelectionPaths();
+    if (selectionPaths == null || selectionPaths.length == 0) {
+      return Breakpoint.EMPTY_ARRAY;
+    }
+    final List<Breakpoint> breakpoints = new ArrayList<Breakpoint>(selectionPaths.length);
+    for (TreePath path : selectionPaths) {
+      final CheckedTreeNode node = (CheckedTreeNode)path.getLastPathComponent();
+      TreeUtil.traverseDepth(node, new TreeUtil.Traverse() {
+        public boolean accept(Object _node) {
+          final CheckedTreeNode node = (CheckedTreeNode)_node;
+          final TreeDescriptor descriptor = (TreeDescriptor)node.getUserObject();
+          if (descriptor instanceof BreakpointDescriptor) {
+            breakpoints.add(((BreakpointDescriptor)descriptor).getBreakpoint());
+          }
+          return true;
+        }
+      });
+    }
+    return breakpoints.toArray(new Breakpoint[breakpoints.size()]);
+  }
+
+  public void selectBreakpoint(Breakpoint breakpoint) {
+    final CheckedTreeNode node = myDescriptorToNodeMap.get(new BreakpointDescriptor(breakpoint));
+    if (node == null) {
+      return;
+    }
+    TreeUtil.selectNode(this, node);
+  }
+
+  public void selectBreakpoints(Breakpoint[] breakpoints) {
+    final List<CheckedTreeNode> nodes = new ArrayList<CheckedTreeNode>(breakpoints.length);
+    for (Breakpoint breakpoint : breakpoints) {
+      final CheckedTreeNode node = myDescriptorToNodeMap.get(new BreakpointDescriptor(breakpoint));
+      if (node != null) {
+        nodes.add(node);
+      }
+    }
+    clearSelection();
+    for (CheckedTreeNode node : nodes) {
+      addSelectionPath(new TreePath(node.getPath()));
+    }
+  }
+
+  public void selectFirstBreakpoint() {
+    TreeUtil.traverseDepth(myRootNode, new TreeUtil.Traverse() {
+      public boolean accept(Object node) {
+        final CheckedTreeNode treeNode = (CheckedTreeNode)node;
+        final TreeDescriptor descriptor = (TreeDescriptor)treeNode.getUserObject();
+        if (descriptor instanceof BreakpointDescriptor) {
+          TreeUtil.selectNode(BreakpointTree.this, treeNode);
+          return false;
+        }
+        return true;
+      }
+    });
+  }
+
+  public List<Breakpoint> getBreakpoints() {
+    return Collections.unmodifiableList(myBreakpoints);
+  }
+
+  public void dispose() {
+    final KeyStroke[] treeStrokes = getRegisteredKeyStrokes();
+    for (KeyStroke stroke : treeStrokes) {
+      unregisterKeyboardAction(stroke);
+    }
+    myBreakpointManager.removeBreakpointManagerListener(myNodeUpdateListener);
+  }
+
+  private abstract static class TreeDescriptor {
+    protected void customizeCellRenderer(final ColoredTreeCellRenderer targetRenderer, CheckedTreeNode node, boolean selected, final boolean checked, boolean expanded, boolean leaf, boolean hasFocus) {
+      targetRenderer.setIcon(getDisplayIcon());
+      targetRenderer.append(getDisplayString(), checked? SimpleTextAttributes.SIMPLE_CELL_ATTRIBUTES : SimpleTextAttributes.GRAYED_ATTRIBUTES);
+    }
+
+    protected abstract String getDisplayString();
+
+    protected abstract Icon getDisplayIcon();
+
+  }
+
+  private final class BreakpointDescriptor extends TreeDescriptor {
+    private final Breakpoint myBreakpoint;
+    public BreakpointDescriptor(Breakpoint breakpoint) {
+      myBreakpoint = breakpoint;
+    }
+    @NotNull
+    public Breakpoint getBreakpoint() {
+      return myBreakpoint;
+    }
+
+    protected Icon getDisplayIcon() {
+      return myBreakpoint instanceof BreakpointWithHighlighter ?
+        myBreakpoint.ENABLED? ((BreakpointWithHighlighter)myBreakpoint).getSetIcon(false) : ((BreakpointWithHighlighter)myBreakpoint).getDisabledIcon(false) : myBreakpoint.getIcon();
+    }
+
+    public String getDisplayString() {
+      return myBreakpoint.getDisplayName();
+    }
+
+    public boolean equals(final Object o) {
+      if (this == o) {
+        return true;
+      }
+      if (o == null || getClass() != o.getClass()) {
+        return false;
+      }
+      final BreakpointDescriptor breakpointDescriptor = (BreakpointDescriptor)o;
+      return myBreakpoint.equals(breakpointDescriptor.myBreakpoint);
+    }
+
+    public int hashCode() {
+      return myBreakpoint.hashCode();
+    }
+
+    public boolean isSlave() {
+      final Breakpoint breakpoint = getBreakpoint();
+      return myBreakpointManager.findMasterBreakpoint(breakpoint) != null;
+    }
+  }
+
+  private static final class MethodDescriptor extends TreeDescriptor {
+    private final String myClassName;
+    private final String myMethodName;
+    @NotNull private final String myPackageName;
+
+    public MethodDescriptor(String methodName, String className, @NotNull String packageName) {
+      myClassName = className;
+      myMethodName = methodName;
+      myPackageName = packageName;
+    }
+
+    @NotNull
+    public String getPackageName() {
+      return myPackageName;
+    }
+
+    public String getClassName() {
+      return myClassName;
+    }
+
+    public String getMethodName() {
+      return myMethodName;
+    }
+
+    protected String getDisplayString() {
+      return myMethodName;
+    }
+
+    protected Icon getDisplayIcon() {
+      return PlatformIcons.METHOD_ICON;
+    }
+
+    public boolean equals(final Object o) {
+      if (this == o) {
+        return true;
+      }
+      if (o == null || getClass() != o.getClass()) {
+        return false;
+      }
+      final MethodDescriptor methodDescriptor = (MethodDescriptor)o;
+      if (!myClassName.equals(methodDescriptor.myClassName)) {
+        return false;
+      }
+      return myMethodName.equals(methodDescriptor.myMethodName);
+    }
+
+    public int hashCode() {
+      int result = myClassName.hashCode();
+      result = 29 * result + myMethodName.hashCode();
+      return result;
+    }
+  }
+
+  private static final class ClassDescriptor extends TreeDescriptor {
+    @NotNull private final String myClassName;
+    @NotNull private final String myPackageName;
+
+    public ClassDescriptor(@NotNull String className, @NotNull String packageName) {
+      myClassName = className;
+      myPackageName = packageName.length() == 0? DEFAULT_PACKAGE_NAME : packageName;
+    }
+
+    @NotNull
+    public String getPackageName() {
+      return myPackageName;
+    }
+
+    @NotNull
+    public String getClassName() {
+      return myClassName;
+    }
+
+    protected String getDisplayString() {
+      return getClassName();
+    }
+
+    protected Icon getDisplayIcon() {
+      return PlatformIcons.CLASS_ICON;
+    }
+
+    public boolean equals(final Object o) {
+      if (this == o) {
+        return true;
+      }
+      if (o == null || getClass() != o.getClass()) {
+        return false;
+      }
+
+      final ClassDescriptor classDescriptor = (ClassDescriptor)o;
+
+      return myClassName.equals(classDescriptor.myClassName);
+
+    }
+
+    public int hashCode() {
+      return myClassName.hashCode();
+    }
+  }
+
+  private static final class PackageDescriptor extends TreeDescriptor {
+    private final String myPackageName;
+
+    public PackageDescriptor(String packageName) {
+      myPackageName = "".equals(packageName)? DEFAULT_PACKAGE_NAME : packageName;
+    }
+
+    public String getPackageName() {
+      return myPackageName;
+    }
+
+    public String getParentPackageName() {
+      final int dotIndex = myPackageName.lastIndexOf('.');
+      return dotIndex >= 0 ? myPackageName.substring(0, dotIndex) : null;
+    }
+
+    public void customizeCellRenderer(final ColoredTreeCellRenderer targetRenderer, CheckedTreeNode node, boolean selected,
+                                      final boolean checked, boolean expanded, boolean leaf, boolean hasFocus) {
+      targetRenderer.setIcon(PlatformIcons.PACKAGE_ICON);
+      final String displayName;
+      final CheckedTreeNode parent = (CheckedTreeNode)node.getParent();
+      if (parent != null && parent.getUserObject() instanceof PackageDescriptor) {
+        final String parentPackageInTree = ((PackageDescriptor)parent.getUserObject()).getPackageName() + ".";
+        displayName = myPackageName.startsWith(parentPackageInTree)? myPackageName.substring(parentPackageInTree.length()) : myPackageName;
+      }
+      else {
+        displayName = myPackageName;
+      }
+      targetRenderer.append(displayName, checked? SimpleTextAttributes.SIMPLE_CELL_ATTRIBUTES : SimpleTextAttributes.GRAYED_ATTRIBUTES);
+    }
+
+    protected String getDisplayString() {
+      return myPackageName;
+    }
+
+    protected Icon getDisplayIcon() {
+      return PlatformIcons.PACKAGE_ICON;
+    }
+
+    public boolean equals(final Object o) {
+      if (this == o) {
+        return true;
+      }
+      if (o == null || getClass() != o.getClass()) {
+        return false;
+      }
+
+      final PackageDescriptor packageDescriptor = (PackageDescriptor)o;
+
+      return myPackageName.equals(packageDescriptor.myPackageName);
+
+    }
+
+    public int hashCode() {
+      return myPackageName.hashCode();
+    }
+  }
+
+  public BreakpointTree(final Project project) {
+    super(new BreakpointTreeCellRenderer(), new CheckedTreeNode(new RootDescriptor()));
+    myRootNode = (CheckedTreeNode)getModel().getRoot();
+    myDescriptorToNodeMap.put((TreeDescriptor)myRootNode.getUserObject(), myRootNode);
+    myBreakpointManager = DebuggerManagerEx.getInstanceEx(project).getBreakpointManager();
+    myNodeUpdateListener = new BreakpointManagerListener() {
+      public void breakpointsChanged() {
+        repaint();
+      }
+    };
+    myBreakpointManager.addBreakpointManagerListener(myNodeUpdateListener);
+    getEmptyText().setText(XDebuggerBundle.message("debugger.no.breakpoints"));
+  }
+
+  public boolean isGroupByMethods() {
+    return myGroupByMethods;
+  }
+
+  public void setGroupByMethods(boolean groupByMethods) {
+    if (myGroupByMethods != groupByMethods) {
+      myGroupByMethods = groupByMethods;
+      rebuildTree();
+    }
+  }
+
+  public boolean isGroupByClasses() {
+    return myGroupByClasses;
+  }
+
+  public void setGroupByClasses(boolean groupByClasses) {
+    if (myGroupByClasses != groupByClasses) {
+      myGroupByClasses = groupByClasses;
+      rebuildTree();
+    }
+  }
+
+  public boolean isFlattenPackages() {
+    return myFlattenPackages;
+  }
+
+  public void setFlattenPackages(boolean flattenPackages) {
+    if (myFlattenPackages != flattenPackages) {
+      myFlattenPackages = flattenPackages;
+      rebuildTree();
+    }
+  }
+
+  @Override
+  protected void onNodeStateChanged(final CheckedTreeNode node) {
+    final Object descriptor = node.getUserObject();
+    final Breakpoint breakpoint;
+    if (descriptor instanceof BreakpointDescriptor) {
+      breakpoint = ((BreakpointDescriptor)descriptor).getBreakpoint();
+      if (myBreakpointManager.findMasterBreakpoint(breakpoint) != null) {
+        return;
+      }
+    }
+    else {
+      breakpoint = null;
+    }
+
+    if (breakpoint != null) {
+      myBreakpointManager.setBreakpointEnabled(breakpoint, node.isChecked());
+    }
+
+  }
+
+  public void addBreakpoint(final Breakpoint breakpoint) {
+    myBreakpoints.add(breakpoint);
+    breakpoint.updateUI(new Runnable() {
+      public void run() {
+        rebuildTree();
+      }
+    });
+    rebuildTree();
+    selectBreakpoint(breakpoint);
+  }
+
+  public void removeBreakpoint(Breakpoint breakpoint) {
+    myBreakpoints.remove(breakpoint);
+    rebuildTree();
+  }
+
+  public void removeBreakpoints(Breakpoint[] breakpoints) {
+    myBreakpoints.removeAll(Arrays.asList(breakpoints));
+    rebuildTree();
+  }
+
+  public void setBreakpoints(Breakpoint[] breakpoints) {
+    myBreakpoints.clear();
+    ContainerUtil.addAll(myBreakpoints, breakpoints);
+    rebuildTree();
+  }
+
+  public Breakpoint getPreviousSibling(Breakpoint breakpoint) {
+    return getSibling(breakpoint, false);
+  }
+
+
+  public Breakpoint getNextSibling(Breakpoint breakpoint) {
+    return getSibling(breakpoint, true);
+  }
+
+  private Breakpoint getSibling(Breakpoint breakpoint, boolean nextSibling) {
+    final CheckedTreeNode node = myDescriptorToNodeMap.get(new BreakpointDescriptor(breakpoint));
+    if (node == null) {
+      return null;
+    }
+    final CheckedTreeNode sibling = (CheckedTreeNode) (nextSibling? node.getNextSibling() : node.getPreviousSibling());
+    if (sibling == null) {
+      return null;
+    }
+    final TreeDescriptor descriptor = (TreeDescriptor)sibling.getUserObject();
+    return descriptor instanceof BreakpointDescriptor ? ((BreakpointDescriptor)descriptor).getBreakpoint() : null;
+  }
+
+  private void rebuildTree() {
+    final TreeStateSnapshot treeStateSnapshot = new TreeStateSnapshot(this);
+    myRootNode.removeAllChildren();
+    myDescriptorToNodeMap.clear();
+    myDescriptorToNodeMap.put((TreeDescriptor)myRootNode.getUserObject(), myRootNode);
+    // build tree
+    for (final Breakpoint breakpoint : myBreakpoints) {
+      CheckedTreeNode node = createNode(new BreakpointDescriptor(breakpoint));
+      node.setChecked(breakpoint.ENABLED);
+      addNode(node);
+    }
+    // remove all package nodes with one child
+    final int count = myRootNode.getChildCount();
+    final List<CheckedTreeNode> children = new ArrayList<CheckedTreeNode>();
+    for (int idx = 0; idx < count; idx++) {
+      CheckedTreeNode child = (CheckedTreeNode)myRootNode.getChildAt(idx);
+      if (!(child.getUserObject() instanceof PackageDescriptor)) {
+        children.add(child);
+        continue;
+      }
+      while (child.getUserObject() instanceof PackageDescriptor && child.getChildCount() <= 1) {
+        child = (CheckedTreeNode)child.getChildAt(0);
+      }
+      if (!(child.getUserObject() instanceof PackageDescriptor)) {
+        child = (CheckedTreeNode)child.getParent();
+      }
+      for (CheckedTreeNode childToRemove = (CheckedTreeNode)child.getParent(); !childToRemove.equals(myRootNode); childToRemove = (CheckedTreeNode)childToRemove.getParent()) {
+        myDescriptorToNodeMap.remove(childToRemove.getUserObject());
+      }
+      children.add(child);
+    }
+    for (final CheckedTreeNode aChildren : children) {
+      aChildren.removeFromParent();
+    }
+    myRootNode.removeAllChildren();
+    for (final CheckedTreeNode child : children) {
+      myRootNode.add(child);
+    }
+    sortChildren(myRootNode);
+    ((DefaultTreeModel)getModel()).nodeStructureChanged(myRootNode);
+    treeStateSnapshot.restore(this);
+    expandPath(new TreePath(myRootNode));
+  }
+
+  private void sortChildren(CheckedTreeNode node) {
+    final int childCount = node.getChildCount();
+    if (childCount == 0) {
+      return;
+    }
+    final List<CheckedTreeNode> children = new ArrayList<CheckedTreeNode>(childCount);
+    for (int idx = 0; idx < childCount; idx++) {
+      children.add((CheckedTreeNode)node.getChildAt(idx));
+    }
+    for (CheckedTreeNode child : children) {
+      sortChildren(child);
+      child.removeFromParent();
+    }
+    Collections.sort(children, myNodeComparator);
+    for (CheckedTreeNode child : children) {
+      node.add(child);
+    }
+  }
+  
+  @NotNull
+  private CheckedTreeNode  createNode(final TreeDescriptor descriptor) {
+    final CheckedTreeNode node = new CheckedTreeNode(descriptor);
+    myDescriptorToNodeMap.put(descriptor, node);
+    return node;
+  }
+
+  /**
+   * @param node
+   */
+  private void addNode(CheckedTreeNode node) {
+    for (final NodeAppender appender : myAppenders) {
+      node = appender.append(node);
+      if (node == null) {
+        break;
+      }
+    }
+    if (node != null) {
+      attachNodeToParent(getDescriptor(myRootNode), node);
+    }
+  }
+
+  private static TreeDescriptor getDescriptor(final CheckedTreeNode node) {
+    return (TreeDescriptor)node.getUserObject();
+  }
+
+  /**
+   * @param parentDescriptor a descriptor of the childNode (possibly not existing) to attach to
+   * @param childNode the childNode to be attached 
+   * @return either parent node if it has just been created or null, if the node has been attached to already existing childNode
+   */
+  private CheckedTreeNode attachNodeToParent(final TreeDescriptor parentDescriptor, final CheckedTreeNode childNode) {
+    CheckedTreeNode parentNode = myDescriptorToNodeMap.get(parentDescriptor);
+    try {
+      if (parentNode != null) {
+        parentNode.add(childNode);
+        return null;  // added to already existing, so stop iteration over appenders
+      }
+      parentNode = createNode(parentDescriptor);
+      parentNode.add(childNode);
+      return parentNode;
+    }
+    finally {
+      if (parentNode != null && parentNode.getChildCount() == 1) {
+        expandPath(new TreePath(parentNode.getPath()));
+      }
+    }
+  }
+
+  private static class BreakpointTreeCellRenderer extends CheckboxTreeCellRenderer {
+    public void customizeRenderer(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
+      if (value instanceof CheckedTreeNode) {
+        final CheckedTreeNode node = (CheckedTreeNode)value;
+        final TreeDescriptor descriptor = getDescriptor(node);
+        descriptor.customizeCellRenderer(getTextRenderer(), node, selected, node.isChecked(), expanded, leaf, hasFocus);
+        if (descriptor instanceof BreakpointDescriptor) {
+          myCheckbox.setEnabled(node.isEnabled() && !((BreakpointDescriptor)descriptor).isSlave());
+        }
+      }
+    }
+  }
+
+  private abstract static class NodeAppender {
+    public abstract CheckedTreeNode append(CheckedTreeNode node);
+  }
+
+  private class BreakpointToMethodAppender extends NodeAppender {
+    public CheckedTreeNode append(CheckedTreeNode node) {
+      if (!myGroupByMethods) {
+        return node;
+      }
+      final TreeDescriptor descriptor = getDescriptor(node);
+      if (!(descriptor instanceof BreakpointDescriptor)) {
+        return node;
+      }
+      final Breakpoint breakpoint = ((BreakpointDescriptor)descriptor).getBreakpoint();
+      if (!(breakpoint instanceof LineBreakpoint)) {
+        return node;
+      }
+      final LineBreakpoint lineBreakpoint = (LineBreakpoint)breakpoint;
+      final String methodName = lineBreakpoint.getMethodName();
+      final String className = lineBreakpoint.getShortClassName();
+      final String packageName = lineBreakpoint.getPackageName();
+      if (methodName == null || className == null || packageName == null) {
+        return node;
+      }
+      return attachNodeToParent(new MethodDescriptor(methodName, className, packageName), node);
+    }
+  }
+
+  private class BreakpointToClassAppender extends NodeAppender {
+    public CheckedTreeNode append(CheckedTreeNode node) {
+      if (!myGroupByClasses) {
+        return node;
+      }
+      final TreeDescriptor descriptor = getDescriptor(node);
+      if (!(descriptor instanceof BreakpointDescriptor)) {
+        return node;
+      }
+      
+      final Breakpoint breakpoint = ((BreakpointDescriptor)descriptor).getBreakpoint();
+      final String className = breakpoint.getShortClassName();
+      if (className == null) {
+        return node;
+      }
+      final String packageName = breakpoint.getPackageName();
+      if (packageName == null) {
+        return node;
+      }
+      return attachNodeToParent(new ClassDescriptor(className, packageName), node);
+    }
+  }
+
+  private class BreakpointToPackageAppender extends NodeAppender {
+    public CheckedTreeNode append(CheckedTreeNode node) {
+      final TreeDescriptor descriptor = getDescriptor(node);
+      if (!(descriptor instanceof BreakpointDescriptor)) {
+        return node;
+      }
+
+      final Breakpoint breakpoint = ((BreakpointDescriptor)descriptor).getBreakpoint();
+      final String packageName;
+      if (breakpoint instanceof ExceptionBreakpoint) {
+        packageName = breakpoint.getPackageName();
+      }
+      else if (breakpoint instanceof BreakpointWithHighlighter) {
+        packageName = breakpoint.getPackageName();
+      }
+      else {
+        packageName = null;
+      }
+      if (packageName == null) {
+        return node;
+      }
+      return attachNodeToParent(new PackageDescriptor(packageName), node);
+    }
+  }
+
+  private class MethodToClassAppender extends NodeAppender {
+    public CheckedTreeNode append(CheckedTreeNode node) {
+      if (!myGroupByClasses) {
+        return node;
+      }
+      final TreeDescriptor descriptor = getDescriptor(node);
+      if (!(descriptor instanceof MethodDescriptor)) {
+        return node;
+      }
+      final MethodDescriptor methodDescriptor = (MethodDescriptor)descriptor;
+      final String className = methodDescriptor.getClassName();
+      final String packageName = methodDescriptor.getPackageName();
+      return attachNodeToParent(new ClassDescriptor(className, packageName), node);
+    }
+  }
+
+  private class MethodToPackageAppender extends NodeAppender {
+    public CheckedTreeNode append(CheckedTreeNode node) {
+      final TreeDescriptor descriptor = getDescriptor(node);
+      if (!(descriptor instanceof MethodDescriptor)) {
+        return node;
+      }
+      final MethodDescriptor methodDescriptor = (MethodDescriptor)descriptor;
+      final String packageName = methodDescriptor.getPackageName();
+      return attachNodeToParent(new PackageDescriptor(packageName), node);
+    }
+  }
+
+  private class ClassToPackageAppender extends NodeAppender {
+    public CheckedTreeNode append(CheckedTreeNode node) {
+      final TreeDescriptor descriptor = getDescriptor(node);
+      if (!(descriptor instanceof ClassDescriptor)) {
+        return node;
+      }
+
+      final String packageName = ((ClassDescriptor)descriptor).getPackageName();
+      return attachNodeToParent(new PackageDescriptor(packageName), node);
+    }
+  }
+
+  private class PackageToPackageAppender extends NodeAppender {
+    public CheckedTreeNode append(CheckedTreeNode node) {
+      if (myFlattenPackages) {
+        return node;
+      }
+      final TreeDescriptor descriptor = getDescriptor(node);
+      if (!(descriptor instanceof PackageDescriptor)) {
+        return node;
+      }
+
+      final PackageDescriptor packageDescriptor = (PackageDescriptor)descriptor;
+      final String parentPackageName = packageDescriptor.getParentPackageName();
+      if (parentPackageName == null) {
+        return node;
+      }
+      final CheckedTreeNode parentNode = attachNodeToParent(new PackageDescriptor(parentPackageName), node);
+      if (parentNode == null) {
+        return null;
+      }
+      return append(parentNode);
+    }
+  }
+
+  private static class RootDescriptor extends TreeDescriptor {
+
+    protected String getDisplayString() {
+      return "";
+    }
+
+    protected Icon getDisplayIcon() {
+      return PlatformIcons.PROJECT_ICON;
+    }
+  }
+  
+  private static class TreeStateSnapshot {
+    private final Object[] myExpandedUserObjects;
+    private final Object[] mySelectedUserObjects;
+
+    public TreeStateSnapshot(BreakpointTree tree) {
+      final List<TreePath> expandedPaths = TreeUtil.collectExpandedPaths(tree);
+      myExpandedUserObjects = getUserObjects(expandedPaths.toArray(new TreePath[expandedPaths.size()]));
+      mySelectedUserObjects =getUserObjects(tree.getSelectionPaths());
+    }
+
+    private static Object[] getUserObjects(final TreePath[] treePaths) {
+      if (treePaths == null) {
+        return ArrayUtil.EMPTY_OBJECT_ARRAY;
+      }
+      Object[] userObjects = new Object[treePaths.length];
+      int index = 0;
+      for (TreePath path : treePaths) {
+        userObjects[index++] = ((CheckedTreeNode)path.getLastPathComponent()).getUserObject();
+      }
+      return userObjects;
+    }
+
+    public void restore(BreakpointTree tree) {
+      final List<TreePath> pathsToExpand = getPaths(tree, myExpandedUserObjects);
+      if (!pathsToExpand.isEmpty()) {
+        TreeUtil.restoreExpandedPaths(tree, pathsToExpand);
+      }
+
+      final List<TreePath> pathsToSelect = getPaths(tree, mySelectedUserObjects);
+      if (!pathsToSelect.isEmpty()) {
+        tree.getSelectionModel().clearSelection();
+        tree.setSelectionPaths(pathsToSelect.toArray(new TreePath[pathsToSelect.size()]));
+      }
+    }
+
+    private static List<TreePath> getPaths(BreakpointTree tree, final Object[] userObjects) {
+      final List<TreePath> paths = new ArrayList<TreePath>(userObjects.length);
+      for (Object descriptor : userObjects) {
+        final CheckedTreeNode node = tree.myDescriptorToNodeMap.get(descriptor);
+        if (node != null) {
+          paths.add(new TreePath(node.getPath()));
+        }
+      }
+      return paths;
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointWithHighlighter.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointWithHighlighter.java
new file mode 100644
index 0000000..a285463
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointWithHighlighter.java
@@ -0,0 +1,737 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.breakpoints;
+
+import com.intellij.CommonBundle;
+import com.intellij.debugger.*;
+import com.intellij.debugger.engine.DebugProcess;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
+import com.intellij.debugger.engine.JVMNameUtil;
+import com.intellij.debugger.engine.events.DebuggerCommandImpl;
+import com.intellij.debugger.engine.requests.RequestManagerImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.settings.DebuggerSettings;
+import com.intellij.debugger.ui.JavaDebuggerSupport;
+import com.intellij.idea.ActionsBundle;
+import com.intellij.openapi.actionSystem.ActionGroup;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.DefaultActionGroup;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.colors.EditorColorsManager;
+import com.intellij.openapi.editor.colors.EditorColorsScheme;
+import com.intellij.openapi.editor.ex.MarkupModelEx;
+import com.intellij.openapi.editor.impl.DocumentMarkupModel;
+import com.intellij.openapi.editor.markup.*;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.*;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.openapi.vfs.VirtualFileManager;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiManager;
+import com.intellij.psi.jsp.JspFile;
+import com.intellij.ui.classFilter.ClassFilter;
+import com.intellij.util.StringBuilderSpinAllocator;
+import com.intellij.xdebugger.impl.DebuggerSupport;
+import com.intellij.xdebugger.impl.actions.EditBreakpointAction;
+import com.intellij.xdebugger.impl.actions.ViewBreakpointsAction;
+import com.intellij.xdebugger.impl.actions.XDebuggerActions;
+import com.intellij.xdebugger.ui.DebuggerColors;
+import com.intellij.xml.util.XmlStringUtil;
+import com.sun.jdi.ReferenceType;
+import org.jdom.Element;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.dnd.DragSource;
+
+/**
+ * User: lex
+ * Date: Sep 2, 2003
+ * Time: 3:22:55 PM
+ */
+public abstract class BreakpointWithHighlighter extends Breakpoint {
+  @Nullable private RangeHighlighter myHighlighter;
+
+  @Nullable private SourcePosition mySourcePosition;
+
+  private boolean myVisible = true;
+  private volatile Icon myIcon = getSetIcon(false);
+  @Nullable private String myClassName;
+  @Nullable private String myPackageName;
+  @Nullable private String myInvalidMessage;
+
+  protected abstract void createRequestForPreparedClass(final DebugProcessImpl debugProcess, final ReferenceType classType);
+
+  protected abstract Icon getDisabledIcon(boolean isMuted);
+
+  protected abstract Icon getInvalidIcon(boolean isMuted);
+
+  protected abstract Icon getSetIcon(boolean isMuted);
+
+  protected abstract Icon getVerifiedIcon(boolean isMuted);
+
+  protected abstract Icon getVerifiedWarningsIcon(boolean isMuted);
+
+  @Override
+  public Icon getIcon() {
+    return myIcon;
+  }
+
+  @Override
+  public String getClassName() {
+    return myClassName;
+  }
+
+  @Override
+  @Nullable
+  public String getShortClassName() {
+    final SourcePosition pos = getSourcePosition();
+    if (pos != null) {
+      if (pos.getFile() instanceof JspFile) {
+        return getClassName();
+      }
+    }
+    return super.getShortClassName();
+  }
+
+  @Override
+  public String getPackageName() {
+    return myPackageName;
+  }
+
+  @Nullable
+  protected Breakpoint init() {
+    if (!isValid()) {
+      myHighlighter.dispose();
+      return null;
+    }
+
+    if (!ApplicationManager.getApplication().isUnitTestMode()) {
+      updateUI();
+      updateGutter();
+    }
+
+    return this;
+  }
+
+  private void updateCaches(DebugProcessImpl debugProcess) {
+    myIcon = calcIcon(debugProcess);
+    myClassName = JVMNameUtil.getSourcePositionClassDisplayName(debugProcess, getSourcePosition());
+    myPackageName = JVMNameUtil.getSourcePositionPackageDisplayName(debugProcess, getSourcePosition());
+  }
+
+  private Icon calcIcon(@Nullable DebugProcessImpl debugProcess) {
+    final boolean muted = debugProcess != null && isMuted(debugProcess);
+    if (!ENABLED) {
+      return getDisabledIcon(muted);
+    }
+
+    myInvalidMessage = "";
+
+    if (!isValid()) {
+      return getInvalidIcon(muted);
+    }
+
+    if (debugProcess == null) {
+      return getSetIcon(muted);
+    }
+
+    final RequestManagerImpl requestsManager = debugProcess.getRequestsManager();
+
+    final boolean isVerified = myCachedVerifiedState || requestsManager.isVerified(this);
+
+    final String warning = requestsManager.getWarning(this);
+    if (warning != null) {
+      myInvalidMessage = warning;
+      if (!isVerified) {
+        return getInvalidIcon(muted);
+      }
+      return getVerifiedWarningsIcon(muted);
+    }
+
+    if (isVerified) {
+      return getVerifiedIcon(muted);
+    }
+
+    return getSetIcon(muted);
+  }
+
+  protected BreakpointWithHighlighter(@NotNull Project project) {
+    //for persistency
+    super(project);
+  }
+
+  public BreakpointWithHighlighter(@NotNull final Project project, @NotNull final RangeHighlighter highlighter) {
+    super(project);
+    myHighlighter = highlighter;
+    highlighter.setEditorFilter(MarkupEditorFilterFactory.createIsNotDiffFilter());
+    reload();
+  }
+
+  public RangeHighlighter getHighlighter() {
+    ApplicationManager.getApplication().assertIsDispatchThread();
+    return myHighlighter;
+  }
+
+  @Override
+  public boolean isValid() {
+    return isPositionValid(getSourcePosition());
+  }
+
+  private static boolean isPositionValid(@Nullable final SourcePosition sourcePosition) {
+    return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
+      @Override
+      public Boolean compute() {
+        return sourcePosition != null && sourcePosition.getFile().isValid() ? Boolean.TRUE : Boolean.FALSE;
+      }
+    }).booleanValue();
+  }
+
+  public SourcePosition getSourcePosition() {
+    return mySourcePosition;
+  }
+
+  @SuppressWarnings("HardCodedStringLiteral")
+  @NotNull
+  public String getDescription() {
+    final StringBuilder buf = StringBuilderSpinAllocator.alloc();
+    try {
+      buf.append("<html><body>");
+      buf.append(getDisplayName());
+      if (myInvalidMessage != null && !myInvalidMessage.isEmpty()) {
+        buf.append("<br><font color='red'>");
+        buf.append(DebuggerBundle.message("breakpoint.warning", myInvalidMessage));
+        buf.append("</font>");
+      }
+      buf.append("&nbsp;<br>&nbsp;");
+      buf.append(DebuggerBundle.message("breakpoint.property.name.suspend.policy")).append(" : ");
+      if (DebuggerSettings.SUSPEND_ALL.equals(SUSPEND_POLICY)) {
+        buf.append(DebuggerBundle.message("breakpoint.properties.panel.option.suspend.all"));
+      }
+      else if (DebuggerSettings.SUSPEND_THREAD.equals(SUSPEND_POLICY)) {
+        buf.append(DebuggerBundle.message("breakpoint.properties.panel.option.suspend.thread"));
+      }
+      else if (DebuggerSettings.SUSPEND_NONE.equals(SUSPEND_POLICY)) {
+        buf.append(DebuggerBundle.message("breakpoint.properties.panel.option.suspend.none"));
+      }
+      buf.append("&nbsp;<br>&nbsp;");
+      buf.append(DebuggerBundle.message("breakpoint.property.name.log.message")).append(": ");
+      buf.append(LOG_ENABLED ? CommonBundle.getYesButtonText() : CommonBundle.getNoButtonText());
+      if (LOG_EXPRESSION_ENABLED) {
+        buf.append("&nbsp;<br>&nbsp;");
+        buf.append(DebuggerBundle.message("breakpoint.property.name.log.expression")).append(": ");
+        buf.append(XmlStringUtil.escapeString(getLogMessage().getText()));
+      }
+      if (CONDITION_ENABLED && getCondition() != null && getCondition().getText() != null && !getCondition().getText().isEmpty()) {
+        buf.append("&nbsp;<br>&nbsp;");
+        buf.append(DebuggerBundle.message("breakpoint.property.name.condition")).append(": ");
+        buf.append(XmlStringUtil.escapeString(getCondition().getText()));
+      }
+      if (COUNT_FILTER_ENABLED) {
+        buf.append("&nbsp;<br>&nbsp;");
+        buf.append(DebuggerBundle.message("breakpoint.property.name.pass.count")).append(": ");
+        buf.append(COUNT_FILTER);
+      }
+      if (CLASS_FILTERS_ENABLED) {
+        buf.append("&nbsp;<br>&nbsp;");
+        buf.append(DebuggerBundle.message("breakpoint.property.name.class.filters")).append(": ");
+        ClassFilter[] classFilters = getClassFilters();
+        for (ClassFilter classFilter : classFilters) {
+          buf.append(classFilter.getPattern()).append(" ");
+        }
+      }
+      if (INSTANCE_FILTERS_ENABLED) {
+        buf.append("&nbsp;<br>&nbsp;");
+        buf.append(DebuggerBundle.message("breakpoint.property.name.instance.filters"));
+        InstanceFilter[] instanceFilters = getInstanceFilters();
+        for (InstanceFilter instanceFilter : instanceFilters) {
+          buf.append(Long.toString(instanceFilter.getId())).append(" ");
+        }
+      }
+      buf.append("</body></html>");
+      return buf.toString();
+    }
+    finally {
+      StringBuilderSpinAllocator.dispose(buf);
+    }
+  }
+
+  @Override
+  public final void reload() {
+    ApplicationManager.getApplication().assertIsDispatchThread();
+    if (getHighlighter().isValid()) {
+      PsiFile psiFile = PsiDocumentManager.getInstance(myProject).getPsiFile(getHighlighter().getDocument());
+      if (psiFile != null) {
+        mySourcePosition = SourcePosition.createFromOffset(psiFile, getHighlighter().getStartOffset());
+        reload(psiFile);
+        return;
+      }
+    }
+    mySourcePosition = null;
+  }
+
+  @Override
+  public void createRequest(@NotNull DebugProcessImpl debugProcess) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    // check is this breakpoint is enabled, vm reference is valid and there're no requests created yet
+    if (!ENABLED ||
+        !debugProcess.isAttached() ||
+        isMuted(debugProcess) ||
+        !debugProcess.getRequestsManager().findRequests(this).isEmpty()) {
+      return;
+    }
+
+    if (!isValid()) {
+      return;
+    }
+
+    createOrWaitPrepare(debugProcess, getSourcePosition());
+    updateUI();
+  }
+
+  protected boolean isMuted(@NotNull final DebugProcessImpl debugProcess) {
+    return debugProcess.areBreakpointsMuted();
+  }
+
+  @Override
+  public void processClassPrepare(final DebugProcess debugProcess, final ReferenceType classType) {
+    if (!ENABLED || !isValid()) {
+      return;
+    }
+    createRequestForPreparedClass((DebugProcessImpl)debugProcess, classType);
+    updateUI();
+  }
+
+
+  /**
+   * updates the state of breakpoint and all the related UI widgets etc
+   */
+  @Override
+  public final void updateUI(@NotNull final Runnable afterUpdate) {
+    if (ApplicationManager.getApplication().isUnitTestMode()) {
+      return;
+    }
+    final Project project = getProject();
+    DebuggerInvocationUtil.swingInvokeLater(project, new Runnable() {
+      @Override
+      public void run() {
+        if (!isValid()) {
+          return;
+        }
+
+        DebuggerContextImpl context = DebuggerManagerEx.getInstanceEx(project).getContext();
+        final DebugProcessImpl debugProcess = context.getDebugProcess();
+
+        if (debugProcess == null || !debugProcess.isAttached()) {
+          updateCaches(null);
+          updateGutter();
+          afterUpdate.run();
+        }
+        else {
+          debugProcess.getManagerThread().invoke(new DebuggerCommandImpl() {
+            @Override
+            protected void action() throws Exception {
+              ApplicationManager.getApplication().runReadAction(new Runnable() {
+                @Override
+                public void run() {
+                  updateCaches(debugProcess);
+                }
+              });
+              DebuggerInvocationUtil.swingInvokeLater(project, new Runnable() {
+                @Override
+                public void run() {
+                  updateGutter();
+                  afterUpdate.run();
+                }
+              });
+            }
+          });
+        }
+      }
+    });
+  }
+
+  private void updateGutter() {
+    if (myVisible) {
+      RangeHighlighter highlighter = getHighlighter();
+      if (highlighter != null && highlighter.isValid() && isValid()) {
+        setupGutterRenderer(highlighter);
+      }
+      else {
+        DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager().removeBreakpoint(this);
+      }
+    }
+  }
+
+  /**
+   * called by BreakpointManager when destroying the breakpoint
+   */
+  @Override
+  public void delete() {
+    if (isVisible()) {
+      final RangeHighlighter highlighter = getHighlighter();
+      if (highlighter != null) {
+        DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
+          @Override
+          public void run() {
+            highlighter.dispose();
+            //we should delete it here, so gutter will not fire events to deleted breakpoint
+            BreakpointWithHighlighter.super.delete();
+          }
+        });
+      }
+    }
+
+  }
+
+  public boolean isAt(@NotNull Document document, int offset) {
+    RangeHighlighter highlighter = getHighlighter();
+    return highlighter != null &&
+           highlighter.isValid() &&
+           document.equals(highlighter.getDocument()) &&
+           getSourcePosition().getLine() == document.getLineNumber(offset);
+  }
+
+  protected void reload(PsiFile psiFile) {
+  }
+
+  @Override
+  public PsiClass getPsiClass() {
+    final SourcePosition sourcePosition = getSourcePosition();
+    return getPsiClassAt(sourcePosition);
+  }
+
+  protected static PsiClass getPsiClassAt(final SourcePosition sourcePosition) {
+    return ApplicationManager.getApplication().runReadAction(new Computable<PsiClass>() {
+      @Nullable
+      @Override
+      public PsiClass compute() {
+        return JVMNameUtil.getClassAt(sourcePosition);
+      }
+    });
+  }
+
+  private void setupGutterRenderer(@NotNull RangeHighlighter highlighter) {
+    MyGutterIconRenderer renderer = new MyGutterIconRenderer(getIcon(), getDescription());
+    highlighter.setGutterIconRenderer(renderer);
+  }
+
+  @Override
+  public abstract Key<? extends BreakpointWithHighlighter> getCategory();
+
+  public boolean canMoveTo(@Nullable final SourcePosition position) {
+    if (position == null || !position.getFile().isValid()) {
+      return false;
+    }
+    final PsiFile psiFile = position.getFile();
+    final Document document = PsiDocumentManager.getInstance(getProject()).getDocument(psiFile);
+    if (document == null) {
+      return false;
+    }
+    final int spOffset = position.getOffset();
+    if (spOffset < 0) {
+      return false;
+    }
+    final BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(getProject()).getBreakpointManager();
+    return breakpointManager.findBreakpoint(document, spOffset, getCategory()) == null;
+  }
+
+  public boolean moveTo(@NotNull SourcePosition position) {
+    if (!canMoveTo(position)) {
+      return false;
+    }
+    final PsiFile psiFile = position.getFile();
+    final PsiFile oldFile = getSourcePosition().getFile();
+    final Document document = PsiDocumentManager.getInstance(getProject()).getDocument(psiFile);
+    final Document oldDocument = PsiDocumentManager.getInstance(getProject()).getDocument(oldFile);
+    if (document == null || oldDocument == null) {
+      return false;
+    }
+    final RangeHighlighter newHighlighter = createHighlighter(myProject, document, position.getLine());
+    if (newHighlighter == null) {
+      return false;
+    }
+    final RangeHighlighter oldHighlighter = myHighlighter;
+    myHighlighter = newHighlighter;
+
+    reload();
+
+    if (!isValid()) {
+      myHighlighter.dispose();
+      myHighlighter = oldHighlighter;
+      reload();
+      return false;
+    }
+
+    oldHighlighter.dispose();
+
+    DebuggerManagerEx.getInstanceEx(getProject()).getBreakpointManager().fireBreakpointChanged(this);
+    updateUI();
+
+    return true;
+  }
+
+  public boolean isVisible() {
+    return myVisible;
+  }
+
+  public void setVisible(boolean visible) {
+    myVisible = visible;
+  }
+
+  @NotNull
+  public Document getDocument() {
+    return getHighlighter().getDocument();
+  }
+
+  public int getLineIndex() {
+    final SourcePosition sourcePosition = getSourcePosition();
+    return sourcePosition != null ? sourcePosition.getLine() : -1;
+  }
+
+  @Nullable
+  protected static RangeHighlighter createHighlighter(@NotNull Project project, @NotNull Document document, int lineIndex) {
+    if (lineIndex < 0 || lineIndex >= document.getLineCount()) {
+      return null;
+    }
+
+    EditorColorsScheme scheme = EditorColorsManager.getInstance().getGlobalScheme();
+    TextAttributes attributes = scheme.getAttributes(DebuggerColors.BREAKPOINT_ATTRIBUTES);
+
+    RangeHighlighter highlighter = ((MarkupModelEx)DocumentMarkupModel.forDocument(document, project, true))
+      .addPersistentLineHighlighter(lineIndex, DebuggerColors.BREAKPOINT_HIGHLIGHTER_LAYER, attributes);
+    if (!highlighter.isValid()) {
+      return null;
+    }
+    highlighter.putUserData(DebuggerColors.BREAKPOINT_HIGHLIGHTER_KEY, Boolean.TRUE);
+    highlighter.setErrorStripeTooltip(DebuggerBundle.message("breakpoint.tooltip.text", lineIndex + 1));
+    return highlighter;
+  }
+
+  @Override
+  public void readExternal(@NotNull Element breakpointNode) throws InvalidDataException {
+    super.readExternal(breakpointNode);
+    //noinspection HardCodedStringLiteral
+    final String url = breakpointNode.getAttributeValue("url");
+
+    //noinspection HardCodedStringLiteral
+    final String className = breakpointNode.getAttributeValue("class");
+    if (className != null) {
+      myClassName = className;
+    }
+
+    //noinspection HardCodedStringLiteral
+    final String packageName = breakpointNode.getAttributeValue("package");
+    if (packageName != null) {
+      myPackageName = packageName;
+    }
+
+    VirtualFile vFile = VirtualFileManager.getInstance().findFileByUrl(url);
+    if (vFile == null) {
+      throw new InvalidDataException(DebuggerBundle.message("error.breakpoint.file.not.found", url));
+    }
+    final Document doc = FileDocumentManager.getInstance().getDocument(vFile);
+    if (doc == null) {
+      throw new InvalidDataException(DebuggerBundle.message("error.cannot.load.breakpoint.file", url));
+    }
+
+    // line number
+    final int line;
+    try {
+      //noinspection HardCodedStringLiteral
+      line = Integer.parseInt(breakpointNode.getAttributeValue("line"));
+    }
+    catch (Exception e) {
+      throw new InvalidDataException("Line number is invalid for breakpoint");
+    }
+    if (line < 0) {
+      throw new InvalidDataException("Line number is invalid for breakpoint");
+    }
+
+    RangeHighlighter highlighter = createHighlighter(myProject, doc, line);
+
+    if (highlighter == null) {
+      throw new InvalidDataException("");
+    }
+
+    myHighlighter = highlighter;
+    reload();
+  }
+
+  @Override
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  public void writeExternal(@NotNull Element parentNode) throws WriteExternalException {
+    super.writeExternal(parentNode);
+    PsiFile psiFile = getSourcePosition().getFile();
+    final VirtualFile virtualFile = psiFile.getVirtualFile();
+    final String url = virtualFile != null ? virtualFile.getUrl() : "";
+    parentNode.setAttribute("url", url);
+    parentNode.setAttribute("line", Integer.toString(getSourcePosition().getLine()));
+    if (myClassName != null) {
+      parentNode.setAttribute("class", myClassName);
+    }
+    if (myPackageName != null) {
+      parentNode.setAttribute("package", myPackageName);
+    }
+  }
+
+  private class MyGutterIconRenderer extends GutterIconRenderer {
+    private final Icon myIcon;
+    private final String myDescription;
+
+    public MyGutterIconRenderer(@NotNull Icon icon, @NotNull String description) {
+      myIcon = icon;
+      myDescription = description;
+    }
+
+    @Override
+    @NotNull
+    public Icon getIcon() {
+      return myIcon;
+    }
+
+    @Override
+    public String getTooltipText() {
+      return myDescription;
+    }
+
+    @Override
+    public AnAction getClickAction() {
+      return new AnAction() {
+        @Override
+        public void actionPerformed(AnActionEvent e) {
+          DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager().removeBreakpoint(BreakpointWithHighlighter.this);
+        }
+      };
+    }
+
+    @Override
+    public AnAction getMiddleButtonClickAction() {
+      return new AnAction() {
+        @Override
+        public void actionPerformed(AnActionEvent e) {
+          ENABLED = !ENABLED;
+          DebuggerManagerEx.getInstanceEx(getProject()).getBreakpointManager().fireBreakpointChanged(BreakpointWithHighlighter.this);
+          updateUI();
+        }
+      };
+    }
+
+    @Override
+    public ActionGroup getPopupMenuActions() {
+      final BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager();
+      /**
+       * Used from Popup Menu
+       */
+      class RemoveAction extends AnAction {
+        @Nullable private Breakpoint myBreakpoint;
+
+        public RemoveAction(Breakpoint breakpoint) {
+          super(DebuggerBundle.message("action.remove.text"));
+          myBreakpoint = breakpoint;
+        }
+
+        @Override
+        public void actionPerformed(AnActionEvent e) {
+          if (myBreakpoint != null) {
+            breakpointManager.removeBreakpoint(myBreakpoint);
+            myBreakpoint = null;
+          }
+        }
+      }
+
+      /**
+       * Used from Popup Menu
+       */
+      class SetEnabledAction extends AnAction {
+        private final boolean myNewValue;
+        private final Breakpoint myBreakpoint;
+
+        public SetEnabledAction(Breakpoint breakpoint, boolean newValue) {
+          super(newValue ? DebuggerBundle.message("action.enable.text") : DebuggerBundle.message("action.disable.text"));
+          myBreakpoint = breakpoint;
+          myNewValue = newValue;
+        }
+
+        @Override
+        public void actionPerformed(AnActionEvent e) {
+          myBreakpoint.ENABLED = myNewValue;
+          breakpointManager.fireBreakpointChanged(myBreakpoint);
+          myBreakpoint.updateUI();
+        }
+      }
+
+
+      AnAction viewBreakpointsAction =
+        new ViewBreakpointsAction(ActionsBundle.actionText(XDebuggerActions.VIEW_BREAKPOINTS), BreakpointWithHighlighter.this);
+
+      DefaultActionGroup group = new DefaultActionGroup();
+      RangeHighlighter highlighter = getHighlighter();
+      if (highlighter != null) {
+        group.add(new EditBreakpointAction.ContextAction(this, BreakpointWithHighlighter.this, DebuggerSupport.getDebuggerSupport(JavaDebuggerSupport.class)));
+        group.addSeparator();
+      }
+      group.add(new SetEnabledAction(BreakpointWithHighlighter.this, !ENABLED));
+      group.add(new RemoveAction(BreakpointWithHighlighter.this));
+      group.addSeparator();
+      group.add(viewBreakpointsAction);
+      return group;
+    }
+
+    @Override
+    public GutterDraggableObject getDraggableObject() {
+      return new GutterDraggableObject() {
+        @Override
+        public boolean copy(int line, @NotNull VirtualFile file) {
+          final PsiFile psiFile = PsiManager.getInstance(getProject()).findFile(file);
+          return psiFile != null && moveTo(SourcePosition.createFromLine(psiFile, line));
+        }
+
+        @Override
+        public Cursor getCursor(int line) {
+          final SourcePosition newPosition = SourcePosition.createFromLine(getSourcePosition().getFile(), line);
+          return canMoveTo(newPosition) ? DragSource.DefaultMoveDrop : DragSource.DefaultMoveNoDrop;
+        }
+      };
+    }
+
+    @Override
+    public boolean equals(@NotNull Object obj) {
+      return obj instanceof MyGutterIconRenderer &&
+             Comparing.equal(getTooltipText(), ((MyGutterIconRenderer)obj).getTooltipText()) &&
+             Comparing.equal(getIcon(), ((MyGutterIconRenderer)obj).getIcon());
+    }
+
+    @Override
+    public int hashCode() {
+      return getIcon().hashCode();
+    }
+
+    @Override
+    public String toString() {
+      return "LB " + getDisplayName();
+    }
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/EditClassFiltersDialog.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/EditClassFiltersDialog.java
new file mode 100644
index 0000000..0f0de4a
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/EditClassFiltersDialog.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class EditClassFiltersDialog
+ * @author Jeka
+ */
+package com.intellij.debugger.ui.breakpoints;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.ide.util.ClassFilter;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.ui.IdeBorderFactory;
+import com.intellij.ui.classFilter.ClassFilterEditor;
+
+import javax.swing.*;
+import java.awt.*;
+
+public class EditClassFiltersDialog extends DialogWrapper {
+  private ClassFilterEditor myClassFilterEditor;
+  private ClassFilterEditor myClassExclusionFilterEditor;
+  private Project myProject;
+  private ClassFilter myChooserFilter;
+
+  public EditClassFiltersDialog(Project project) {
+    this(project, null);
+  }
+
+  public EditClassFiltersDialog(Project project, ClassFilter filter) {
+    super(project, true);
+    myChooserFilter = filter;
+    myProject = project;
+    setTitle(DebuggerBundle.message("class.filters.dialog.title"));
+    init();
+  }
+
+
+  protected JComponent createCenterPanel() {
+    JPanel contentPanel = new JPanel(new BorderLayout());
+
+    Box mainPanel = Box.createHorizontalBox();
+
+    myClassFilterEditor = new ClassFilterEditor(myProject, myChooserFilter, "reference.viewBreakpoints.classFilters.newPattern");
+    myClassFilterEditor.setPreferredSize(new Dimension(400, 200));
+    myClassFilterEditor.setBorder(IdeBorderFactory.createTitledBorder(
+      DebuggerBundle.message("class.filters.dialog.inclusion.filters.group"), false));
+    mainPanel.add(myClassFilterEditor);
+
+    myClassExclusionFilterEditor = new ClassFilterEditor(myProject, myChooserFilter, "reference.viewBreakpoints.classFilters.newPattern");
+    myClassExclusionFilterEditor.setPreferredSize(new Dimension(400, 200));
+    myClassExclusionFilterEditor.setBorder(IdeBorderFactory.createTitledBorder(
+      DebuggerBundle.message("class.filters.dialog.exclusion.filters.group"), false));
+    mainPanel.add(myClassExclusionFilterEditor);
+
+    contentPanel.add(mainPanel, BorderLayout.CENTER);
+
+    return contentPanel;
+  }
+
+  public void dispose(){
+    myClassFilterEditor.stopEditing();
+    super.dispose();
+  }
+
+  public void setFilters(com.intellij.ui.classFilter.ClassFilter[] filters, com.intellij.ui.classFilter.ClassFilter[] inverseFilters) {
+    myClassFilterEditor.setFilters(filters);
+    myClassExclusionFilterEditor.setFilters(inverseFilters);
+  }
+
+  protected String getDimensionServiceKey(){
+    return "#com.intellij.debugger.ui.breakpoints.EditClassFiltersDialog";
+  }
+
+  public com.intellij.ui.classFilter.ClassFilter[] getFilters() {
+    return myClassFilterEditor.getFilters();
+  }
+
+  public com.intellij.ui.classFilter.ClassFilter[] getExclusionFilters() {
+    return myClassExclusionFilterEditor.getFilters();
+  }
+
+  protected String getHelpId() {
+    return "reference.viewBreakpoints.classFilters";
+  }
+}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/EditInstanceFiltersDialog.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/EditInstanceFiltersDialog.java
new file mode 100644
index 0000000..dbc2111
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/EditInstanceFiltersDialog.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.breakpoints;
+
+import com.intellij.ui.classFilter.ClassFilter;
+import com.intellij.debugger.InstanceFilter;
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.ui.InstanceFilterEditor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.ui.IdeBorderFactory;
+
+import javax.swing.*;
+import java.awt.*;
+
+/**
+ * User: lex
+ * Date: Aug 29, 2003
+ * Time: 2:44:38 PM
+ */
+public class EditInstanceFiltersDialog extends DialogWrapper{
+  private InstanceFilterEditor myInstanceFilterEditor;
+  private final Project myProject;
+
+  public EditInstanceFiltersDialog (Project project) {
+    super(project, true);
+    myProject = project;
+    setTitle(DebuggerBundle.message("instance.filters.dialog.title"));
+    init();
+  }
+
+  protected JComponent createCenterPanel() {
+    JPanel contentPanel = new JPanel(new BorderLayout());
+
+    Box mainPanel = Box.createHorizontalBox();
+
+    myInstanceFilterEditor = new InstanceFilterEditor(myProject);
+    myInstanceFilterEditor.setPreferredSize(new Dimension(400, 200));
+    myInstanceFilterEditor.setBorder(IdeBorderFactory.createTitledBorder(
+      DebuggerBundle.message("instance.filters.dialog.instance.filters.group"), false));
+    mainPanel.add(myInstanceFilterEditor);
+
+    contentPanel.add(mainPanel, BorderLayout.CENTER);
+
+    return contentPanel;
+  }
+
+  public void dispose(){
+    myInstanceFilterEditor.stopEditing();
+    super.dispose();
+  }
+
+  public void setFilters(InstanceFilter[] filters) {
+    ClassFilter[] cFilters = InstanceFilter.createClassFilters(filters);
+    myInstanceFilterEditor.setFilters(cFilters);
+  }
+
+  protected String getDimensionServiceKey(){
+    return "#com.intellij.debugger.ui.breakpoints.EditInstanceFiltersDialog";
+  }
+
+  public InstanceFilter[] getFilters() {
+    ClassFilter [] cFilters = myInstanceFilterEditor.getFilters();
+    InstanceFilter [] ifilters = new InstanceFilter[cFilters.length];
+    for (int i = 0; i < ifilters.length; i++) {
+      ifilters[i] = InstanceFilter.create(cFilters[i]);
+    }
+    return ifilters;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/EnableBreakpointRule.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/EnableBreakpointRule.java
new file mode 100644
index 0000000..bcda420
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/EnableBreakpointRule.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.breakpoints;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: May 10, 2005
+ */
+public class EnableBreakpointRule {
+  private final BreakpointManager myManager;
+  private final boolean myLeaveEnabled;
+  private final Breakpoint myMasterBreakpoint;
+  private final Breakpoint mySlaveBreakpoint;
+
+  public EnableBreakpointRule(@NotNull BreakpointManager manager, @NotNull Breakpoint masterBreakpoint, @NotNull Breakpoint slaveBreakpoint) {
+    this(manager,masterBreakpoint, slaveBreakpoint, false);
+  }
+
+  public EnableBreakpointRule(@NotNull BreakpointManager manager, @NotNull Breakpoint masterBreakpoint, @NotNull Breakpoint slaveBreakpoint, boolean leaveEnabled) {
+    myMasterBreakpoint = masterBreakpoint;
+    mySlaveBreakpoint = slaveBreakpoint;
+    myManager = manager;
+    myLeaveEnabled = leaveEnabled;
+  }
+
+  public Breakpoint getMasterBreakpoint() {
+    return myMasterBreakpoint;
+  }
+
+  public Breakpoint getSlaveBreakpoint() {
+    return mySlaveBreakpoint;
+  }
+
+  public boolean isLeaveEnabled() {
+    return myLeaveEnabled;
+  }
+
+  public void init() {
+    myManager.setBreakpointEnabled(getSlaveBreakpoint(), false);
+  }
+
+  public void dispose() {
+    myManager.setBreakpointEnabled(getSlaveBreakpoint(), true);
+  }
+
+  public void processBreakpointHit(Breakpoint breakpointHit) {
+    if (getMasterBreakpoint().equals(breakpointHit)) {
+      myManager.setBreakpointEnabled(getSlaveBreakpoint(), true);
+    }
+    else if (getSlaveBreakpoint().equals(breakpointHit)){
+      if (!myLeaveEnabled) {
+        myManager.setBreakpointEnabled(getSlaveBreakpoint(), false);
+      }
+    }
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpoint.java
new file mode 100644
index 0000000..c6a1955
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpoint.java
@@ -0,0 +1,250 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class ExceptionBreakpoint
+ * @author Jeka
+ */
+package com.intellij.debugger.ui.breakpoints;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.SourcePosition;
+import com.intellij.debugger.engine.DebugProcess;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
+import com.intellij.debugger.engine.SuspendContextImpl;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.icons.AllIcons;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Computable;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.Key;
+import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.psi.JavaPsiFacade;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.sun.jdi.AbsentInformationException;
+import com.sun.jdi.Location;
+import com.sun.jdi.ObjectReference;
+import com.sun.jdi.ReferenceType;
+import com.sun.jdi.event.ExceptionEvent;
+import com.sun.jdi.event.LocatableEvent;
+import com.sun.jdi.request.ExceptionRequest;
+import org.jdom.Element;
+import org.jetbrains.annotations.NonNls;
+
+import javax.swing.*;
+
+public class ExceptionBreakpoint extends Breakpoint {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.breakpoints.ExceptionBreakpoint");
+
+  public boolean NOTIFY_CAUGHT   = true;
+  public boolean NOTIFY_UNCAUGHT = true;
+  private String myQualifiedName;
+  private String myPackageName;
+
+  protected final static String READ_NO_CLASS_NAME = DebuggerBundle.message("error.absent.exception.breakpoint.class.name");
+  public static final @NonNls Key<ExceptionBreakpoint> CATEGORY = BreakpointCategory.lookup("exception_breakpoints");
+
+  public ExceptionBreakpoint(Project project) {
+    super(project);
+  }
+
+  public Key<? extends ExceptionBreakpoint> getCategory() {
+    return CATEGORY;
+  }
+
+  protected ExceptionBreakpoint(Project project, String qualifiedName, String packageName) {
+    super(project);
+    myQualifiedName = qualifiedName;
+    if (packageName == null) {
+      myPackageName = calcPackageName(qualifiedName);
+    }
+    else {
+      myPackageName = packageName;
+    }
+  }
+
+  private String calcPackageName(String qualifiedName) {
+    if (qualifiedName == null) {
+      return null;
+    }
+    int dotIndex = qualifiedName.lastIndexOf('.');
+    return dotIndex >= 0? qualifiedName.substring(0, dotIndex) : "";
+  }
+
+  public String getClassName() {
+    return myQualifiedName;
+  }
+
+  public String getPackageName() {
+    return myPackageName;
+  }
+
+  public PsiClass getPsiClass() {
+    return PsiDocumentManager.getInstance(myProject).commitAndRunReadAction(new Computable<PsiClass>() {
+      public PsiClass compute() {
+        return myQualifiedName != null ? DebuggerUtilsEx.findClass(myQualifiedName, myProject, GlobalSearchScope.allScope(myProject)) : null;
+      }
+    });
+  }
+
+  public String getDisplayName() {
+    return DebuggerBundle.message("breakpoint.exception.breakpoint.display.name", myQualifiedName);
+  }
+
+  public Icon getIcon() {
+    if (!ENABLED) {
+      final Breakpoint master = DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager().findMasterBreakpoint(this);
+      return master == null? AllIcons.Debugger.Db_disabled_exception_breakpoint : AllIcons.Debugger.Db_dep_exception_breakpoint;
+    }
+    return AllIcons.Debugger.Db_exception_breakpoint;
+  }
+
+  public void reload() {
+  }
+
+  public void createRequest(final DebugProcessImpl debugProcess) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    if (!ENABLED || !debugProcess.isAttached() || debugProcess.areBreakpointsMuted() || !debugProcess.getRequestsManager().findRequests(this).isEmpty()) {
+      return;
+    }
+
+    SourcePosition classPosition = PsiDocumentManager.getInstance(myProject).commitAndRunReadAction(new Computable<SourcePosition>() {
+      public SourcePosition compute() {
+        PsiClass psiClass = DebuggerUtilsEx.findClass(myQualifiedName, myProject, debugProcess.getSearchScope());
+
+        return psiClass != null ? SourcePosition.createFromElement(psiClass) : null;
+      }
+    });
+
+    if(classPosition == null) {
+      createOrWaitPrepare(debugProcess, myQualifiedName);
+    }
+    else {
+      createOrWaitPrepare(debugProcess, classPosition);
+    }
+  }
+
+  public void processClassPrepare(DebugProcess process, ReferenceType refType) {
+    DebugProcessImpl debugProcess = (DebugProcessImpl)process;
+    if (!ENABLED) {
+      return;
+    }
+    // trying to create a request
+    ExceptionRequest request = debugProcess.getRequestsManager().createExceptionRequest(this, refType, NOTIFY_CAUGHT, NOTIFY_UNCAUGHT);
+    debugProcess.getRequestsManager().enableRequest(request);
+    if (LOG.isDebugEnabled()) {
+      if (refType != null) {
+        LOG.debug("Created exception request for reference type " + refType.name());
+      }
+      else {
+        LOG.debug("Created exception request for reference type null");
+      }
+    }
+  }
+
+  protected ObjectReference getThisObject(SuspendContextImpl context, LocatableEvent event) throws EvaluateException {
+    if(event instanceof ExceptionEvent) {
+      return ((ExceptionEvent) event).exception();
+    }
+    return super.getThisObject(context, event);    //To change body of overriden methods use Options | File Templates.
+  }
+
+  public String getEventMessage(LocatableEvent event) {
+    String exceptionName = (myQualifiedName != null)? myQualifiedName : "java.lang.Throwable";
+    String threadName    = null;
+    if (event instanceof ExceptionEvent) {
+      ExceptionEvent exceptionEvent = (ExceptionEvent)event;
+      try {
+        exceptionName = exceptionEvent.exception().type().name();
+        threadName = exceptionEvent.thread().name();
+      }
+      catch (Exception e) {
+      }
+    }
+    final Location location = event.location();
+    final String locationQName = location.declaringType().name() + "." + location.method().name();
+    String locationFileName = "";
+    try {
+      locationFileName = location.sourceName();
+    }
+    catch (AbsentInformationException e) {
+      locationFileName = "";
+    }
+    final int locationLine = Math.max(0, location.lineNumber());
+    if (threadName != null) {
+      return DebuggerBundle.message(
+        "exception.breakpoint.console.message.with.thread.info", 
+        exceptionName, 
+        threadName,
+        locationQName,
+        locationFileName,
+        locationLine
+      );
+    }
+    else {
+      return DebuggerBundle.message(
+        "exception.breakpoint.console.message", 
+        exceptionName,
+        locationQName,
+        locationFileName,
+        locationLine
+      );
+    }
+  }
+
+  public boolean isValid() {
+    return true;
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"}) public void writeExternal(Element parentNode) throws WriteExternalException {
+    super.writeExternal(parentNode);
+    if(myQualifiedName != null) {
+      parentNode.setAttribute("class_name", myQualifiedName);
+    }
+    if(myPackageName != null) {
+      parentNode.setAttribute("package_name", myPackageName);
+    }
+  }
+
+  public PsiElement getEvaluationElement() {
+    if (getClassName() == null) {
+      return null;
+    }
+    return JavaPsiFacade.getInstance(myProject).findClass(getClassName(), GlobalSearchScope.allScope(myProject));
+  }
+
+  public void readExternal(Element parentNode) throws InvalidDataException {
+    super.readExternal(parentNode);
+    //noinspection HardCodedStringLiteral
+    String className = parentNode.getAttributeValue("class_name");
+    myQualifiedName = className;
+    if(className == null) {
+      throw new InvalidDataException(READ_NO_CLASS_NAME);
+    }
+
+    //noinspection HardCodedStringLiteral
+    String packageName = parentNode.getAttributeValue("package_name");
+    myPackageName = packageName != null? packageName : calcPackageName(packageName);
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpointFactory.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpointFactory.java
new file mode 100644
index 0000000..f1742f0
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpointFactory.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.breakpoints;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.HelpID;
+import com.intellij.debugger.engine.JVMNameUtil;
+import com.intellij.debugger.ui.breakpoints.actions.*;
+import com.intellij.icons.AllIcons;
+import com.intellij.ide.util.TreeClassChooser;
+import com.intellij.ide.util.TreeClassChooserFactory;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.openapi.util.Key;
+import com.intellij.psi.JavaPsiFacade;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiClassOwner;
+import com.intellij.psi.search.GlobalSearchScope;
+import org.jdom.Element;
+
+import javax.swing.*;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: Apr 26, 2005
+ */
+public class ExceptionBreakpointFactory extends BreakpointFactory {
+  public Breakpoint createBreakpoint(Project project, final Element element) {
+    return new ExceptionBreakpoint(project);
+  }
+
+  public Icon getIcon() {
+    return AllIcons.Debugger.Db_exception_breakpoint;
+  }
+
+  public Icon getDisabledIcon() {
+    return AllIcons.Debugger.Db_disabled_exception_breakpoint;
+  }
+
+  @Override
+  protected String getHelpID() {
+    return HelpID.EXCEPTION_BREAKPOINTS;
+  }
+
+  @Override
+  public String getDisplayName() {
+    return DebuggerBundle.message("exception.breakpoints.tab.title");
+  }
+
+  @Override
+  protected void configureBreakpointPanel(BreakpointPanel panel) {
+    super.configureBreakpointPanel(panel);
+    panel.getTree().setGroupByMethods(false);
+  }
+
+  @Override
+  public BreakpointPropertiesPanel createBreakpointPropertiesPanel(Project project, boolean compact) {
+    return new ExceptionBreakpointPropertiesPanel(project, compact);
+  }
+
+  @Override
+  protected BreakpointPanelAction[] createBreakpointPanelActions(final Project project, DialogWrapper parentDialog) {
+    return new BreakpointPanelAction[]{
+      new SwitchViewAction(),
+      new AddAction(this, project),
+      new RemoveAction(project) {
+      public void update() {
+        super.update();
+        if (getButton().isEnabled()) {
+          Breakpoint[] selectedBreakpoints = getPanel().getSelectedBreakpoints();
+          for (Breakpoint bp : selectedBreakpoints) {
+            if (bp instanceof AnyExceptionBreakpoint) {
+              getButton().setEnabled(false);
+            }
+          }
+        }
+      }
+    }, new ToggleGroupByClassesAction(), new ToggleFlattenPackagesAction(),};
+  }
+
+  public BreakpointPanel createBreakpointPanel(final Project project, final DialogWrapper parentDialog) {
+    BreakpointPanel panel =
+      new BreakpointPanel(project, createBreakpointPropertiesPanel(project, false), createBreakpointPanelActions(project, parentDialog),
+                          getBreakpointCategory(), getDisplayName(), getHelpID()) {
+        public void resetBreakpoints() {
+          super.resetBreakpoints();
+          Breakpoint[] breakpoints = getBreakpointManager().getBreakpoints(getBreakpointCategory());
+          final AnyExceptionBreakpoint anyExceptionBreakpoint =
+            DebuggerManagerEx.getInstanceEx(project).getBreakpointManager().getAnyExceptionBreakpoint();
+          boolean found = false;
+          for (Breakpoint breakpoint : breakpoints) {
+            if (breakpoint.equals(anyExceptionBreakpoint)) {
+              found = true;
+              break;
+            }
+          }
+          if (!found) {
+            insertBreakpointAt(anyExceptionBreakpoint, 0);
+          }
+        }
+      };
+    configureBreakpointPanel(panel);
+    return panel;
+  }
+
+  public Key<ExceptionBreakpoint> getBreakpointCategory() {
+    return ExceptionBreakpoint.CATEGORY;
+  }
+
+  @Override
+  public boolean canAddBreakpoints() {
+    return true;
+  }
+
+  @Override
+  public Breakpoint addBreakpoint(Project project) {
+    ExceptionBreakpoint breakpoint = null;
+    final PsiClass throwableClass =
+      JavaPsiFacade.getInstance(project).findClass("java.lang.Throwable", GlobalSearchScope.allScope(project));
+    TreeClassChooser chooser = TreeClassChooserFactory.getInstance(project)
+      .createInheritanceClassChooser(DebuggerBundle.message("add.exception.breakpoint.classchooser.title"),
+                                     GlobalSearchScope.allScope(project), throwableClass, true, true, null);
+    chooser.showDialog();
+    PsiClass selectedClass = chooser.getSelected();
+    String qName = selectedClass == null ? null : JVMNameUtil.getNonAnonymousClassName(selectedClass);
+
+    if (qName != null && qName.length() > 0) {
+      breakpoint = DebuggerManagerEx.getInstanceEx(project).getBreakpointManager()
+        .addExceptionBreakpoint(qName, ((PsiClassOwner)selectedClass.getContainingFile()).getPackageName());
+    }
+    return breakpoint;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpointPropertiesPanel.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpointPropertiesPanel.java
new file mode 100644
index 0000000..73680f5
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpointPropertiesPanel.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class ExceptionBreakpointPropertiesPanel
+ * @author Jeka
+ */
+package com.intellij.debugger.ui.breakpoints;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.ide.util.ClassFilter;
+import com.intellij.openapi.project.Project;
+import com.intellij.ui.IdeBorderFactory;
+import com.intellij.util.ui.DialogUtil;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+public class ExceptionBreakpointPropertiesPanel extends BreakpointPropertiesPanel {
+  private JCheckBox myNotifyCaughtCheckBox;
+  private JCheckBox myNotifyUncaughtCheckBox;
+  private ExceptionBreakpoint myExceptionBreakpoint;
+
+  public ExceptionBreakpointPropertiesPanel(Project project, boolean compact) {
+    super(project, ExceptionBreakpoint.CATEGORY, compact);
+  }
+
+  protected ClassFilter createClassConditionFilter() {
+    return null;
+  }
+
+  protected JComponent createSpecialBox() {
+
+    myNotifyCaughtCheckBox = new JCheckBox(DebuggerBundle.message("label.exception.breakpoint.properties.panel.caught.exception"));
+    myNotifyUncaughtCheckBox = new JCheckBox(DebuggerBundle.message("label.exception.breakpoint.properties.panel.uncaught.exception"));
+    DialogUtil.registerMnemonic(myNotifyCaughtCheckBox);
+    DialogUtil.registerMnemonic(myNotifyUncaughtCheckBox);
+
+
+    Box notificationsBox = Box.createVerticalBox();
+    JPanel _panel = new JPanel(new BorderLayout());
+    _panel.add(myNotifyCaughtCheckBox, BorderLayout.NORTH);
+    notificationsBox.add(_panel);
+    _panel = new JPanel(new BorderLayout());
+    _panel.add(myNotifyUncaughtCheckBox, BorderLayout.NORTH);
+    notificationsBox.add(_panel);
+
+    _panel = new JPanel(new BorderLayout());
+    JPanel _panel0 = new JPanel(new BorderLayout());
+    _panel0.add(notificationsBox, BorderLayout.CENTER);
+    _panel0.add(Box.createHorizontalStrut(3), BorderLayout.WEST);
+    _panel0.add(Box.createHorizontalStrut(3), BorderLayout.EAST);
+    _panel.add(_panel0, BorderLayout.NORTH);
+    _panel.setBorder(IdeBorderFactory.createTitledBorder(
+      DebuggerBundle.message("label.exception.breakpoint.properties.panel.group.notifications"), true));
+
+    ActionListener listener = new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        if (!myNotifyCaughtCheckBox.isSelected() && !myNotifyUncaughtCheckBox.isSelected()) {
+          Object source = e.getSource();
+          JCheckBox toCheck = null;
+          if (myNotifyCaughtCheckBox.equals(source)) {
+            toCheck = myNotifyUncaughtCheckBox;
+          }
+          else if (myNotifyUncaughtCheckBox.equals(source)) {
+            toCheck = myNotifyCaughtCheckBox;
+          }
+          if (toCheck != null) {
+            toCheck.setSelected(true);
+          }
+        }
+      }
+    };
+    myNotifyCaughtCheckBox.addActionListener(listener);
+    myNotifyUncaughtCheckBox.addActionListener(listener);
+    return _panel;
+  }
+
+  protected void updateCheckboxes() {
+    super.updateCheckboxes();
+    myPassCountCheckbox.setEnabled(!(myExceptionBreakpoint instanceof AnyExceptionBreakpoint));
+  }
+
+  public void initFrom(Breakpoint breakpoint, boolean moreOptionsVisible) {
+    ExceptionBreakpoint exceptionBreakpoint = (ExceptionBreakpoint)breakpoint;
+    myExceptionBreakpoint = exceptionBreakpoint;
+    super.initFrom(breakpoint, moreOptionsVisible);
+
+    myNotifyCaughtCheckBox.setSelected(exceptionBreakpoint.NOTIFY_CAUGHT);
+    myNotifyUncaughtCheckBox.setSelected(exceptionBreakpoint.NOTIFY_UNCAUGHT);
+  }
+
+  public void saveTo(Breakpoint breakpoint, @NotNull Runnable afterUpdate) {
+    ExceptionBreakpoint exceptionBreakpoint = (ExceptionBreakpoint)breakpoint;
+    exceptionBreakpoint.NOTIFY_CAUGHT = myNotifyCaughtCheckBox.isSelected();
+    exceptionBreakpoint.NOTIFY_UNCAUGHT = myNotifyUncaughtCheckBox.isSelected();
+
+    super.saveTo(breakpoint, afterUpdate);
+  }
+}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FieldBreakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FieldBreakpoint.java
new file mode 100644
index 0000000..365ae24
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FieldBreakpoint.java
@@ -0,0 +1,393 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class FieldBreakpoint
+ * @author Jeka
+ */
+package com.intellij.debugger.ui.breakpoints;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.SourcePosition;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.SuspendContextImpl;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.jdi.VirtualMachineProxy;
+import com.intellij.debugger.engine.requests.RequestManagerImpl;
+import com.intellij.debugger.impl.PositionUtil;
+import com.intellij.icons.AllIcons;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.markup.RangeHighlighter;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Computable;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.Key;
+import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.openapi.vfs.VirtualFileManager;
+import com.intellij.psi.*;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.util.Processor;
+import com.intellij.util.text.CharArrayUtil;
+import com.intellij.xdebugger.XDebuggerUtil;
+import com.sun.jdi.*;
+import com.sun.jdi.event.AccessWatchpointEvent;
+import com.sun.jdi.event.LocatableEvent;
+import com.sun.jdi.event.ModificationWatchpointEvent;
+import com.sun.jdi.request.AccessWatchpointRequest;
+import com.sun.jdi.request.ModificationWatchpointRequest;
+import org.jdom.Element;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import java.util.List;
+
+public class FieldBreakpoint extends BreakpointWithHighlighter {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.breakpoints.FieldBreakpoint");
+  public boolean WATCH_MODIFICATION = true;
+  public boolean WATCH_ACCESS       = false;
+  private boolean myIsStatic;
+  private String myFieldName;
+
+  @NonNls public static final Key<FieldBreakpoint> CATEGORY = BreakpointCategory.lookup("field_breakpoints");
+
+  protected FieldBreakpoint(Project project) {
+    super(project);
+  }
+
+  private FieldBreakpoint(Project project, RangeHighlighter highlighter, @NotNull String fieldName) {
+    super(project, highlighter);
+    myFieldName = fieldName;
+  }
+
+  public boolean isStatic() {
+    return myIsStatic;
+  }
+
+  public String getFieldName() {
+    return myFieldName;
+  }
+
+
+  @Override
+  protected Icon getDisabledIcon(boolean isMuted) {
+    final Breakpoint master = DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager().findMasterBreakpoint(this);
+    if (isMuted) {
+      return master == null? AllIcons.Debugger.Db_muted_disabled_field_breakpoint : AllIcons.Debugger.Db_muted_dep_field_breakpoint;
+    }
+    else {
+      return master == null? AllIcons.Debugger.Db_disabled_field_breakpoint : AllIcons.Debugger.Db_dep_field_breakpoint;
+    }
+  }
+
+  @Override
+  protected Icon getSetIcon(boolean isMuted) {
+    return isMuted? AllIcons.Debugger.Db_muted_field_breakpoint : AllIcons.Debugger.Db_field_breakpoint;
+  }
+
+  @Override
+  protected Icon getInvalidIcon(boolean isMuted) {
+    return isMuted? AllIcons.Debugger.Db_muted_invalid_field_breakpoint : AllIcons.Debugger.Db_invalid_field_breakpoint;
+  }
+
+  @Override
+  protected Icon getVerifiedIcon(boolean isMuted) {
+    return isMuted? AllIcons.Debugger.Db_muted_verified_field_breakpoint : AllIcons.Debugger.Db_verified_field_breakpoint;
+  }
+
+  @Override
+  protected Icon getVerifiedWarningsIcon(boolean isMuted) {
+    return isMuted? AllIcons.Debugger.Db_muted_field_warning_breakpoint : AllIcons.Debugger.Db_field_warning_breakpoint;
+  }
+
+  @Override
+  public Key<FieldBreakpoint> getCategory() {
+    return CATEGORY;
+  }
+
+  public PsiField getPsiField() {
+    final SourcePosition sourcePosition = getSourcePosition();
+    final PsiField field = ApplicationManager.getApplication().runReadAction(new Computable<PsiField>() {
+      @Override
+      public PsiField compute() {
+        final PsiClass psiClass = getPsiClassAt(sourcePosition);
+        return psiClass != null ? psiClass.findFieldByName(myFieldName, true) : null;
+      }
+    });
+    if (field != null) {
+      return field;
+    }
+    return PositionUtil.getPsiElementAt(getProject(), PsiField.class, sourcePosition);
+  }
+
+  @Override
+  protected void reload(PsiFile psiFile) {
+    super.reload(psiFile);
+    PsiField field = PositionUtil.getPsiElementAt(getProject(), PsiField.class, getSourcePosition());
+    if(field != null) {
+      myFieldName = field.getName();
+      myIsStatic = field.hasModifierProperty(PsiModifier.STATIC);
+    }
+    if (myIsStatic) {
+      INSTANCE_FILTERS_ENABLED = false;
+    }
+  }
+
+  @Override
+  public boolean moveTo(@NotNull SourcePosition position) {
+    final PsiField field = PositionUtil.getPsiElementAt(getProject(), PsiField.class, position);
+    return field != null && super.moveTo(SourcePosition.createFromElement(field));
+  }
+
+  @Override
+  protected ObjectReference getThisObject(SuspendContextImpl context, LocatableEvent event) throws EvaluateException {
+    if (event instanceof ModificationWatchpointEvent) {
+      ModificationWatchpointEvent modificationEvent = (ModificationWatchpointEvent)event;
+      ObjectReference reference = modificationEvent.object();
+      if (reference != null) {  // non-static
+        return reference;
+      }
+    }
+    else if (event instanceof AccessWatchpointEvent) {
+      AccessWatchpointEvent accessEvent = (AccessWatchpointEvent)event;
+      ObjectReference reference = accessEvent.object();
+      if (reference != null) { // non-static
+        return reference;
+      }
+    }
+
+    return super.getThisObject(context, event);
+  }
+
+  @Override
+  public void createRequestForPreparedClass(DebugProcessImpl debugProcess,
+                                            ReferenceType refType) {
+    VirtualMachineProxy vm = debugProcess.getVirtualMachineProxy();
+    try {
+      Field field = refType.fieldByName(myFieldName);
+      if (field == null) {
+        debugProcess.getRequestsManager().setInvalid(this, DebuggerBundle.message("error.invalid.breakpoint.missing.field.in.class", myFieldName, refType.name()));
+        return;
+      }
+      RequestManagerImpl manager = debugProcess.getRequestsManager();
+      if (WATCH_MODIFICATION && vm.canWatchFieldModification()) {
+        ModificationWatchpointRequest request = manager.createModificationWatchpointRequest(this, field);
+        debugProcess.getRequestsManager().enableRequest(request);
+        if (LOG.isDebugEnabled()) {
+          LOG.debug("Modification request added");
+        }
+      }
+      if (WATCH_ACCESS && vm.canWatchFieldAccess()) {
+        AccessWatchpointRequest request = manager.createAccessWatchpointRequest(this, field);
+        debugProcess.getRequestsManager().enableRequest(request);
+        if (LOG.isDebugEnabled()) {
+          LOG.debug("Access request added field = "+field.name() + "; refType = "+refType.name());
+        }
+      }
+    }
+    catch (ObjectCollectedException ex) {
+      LOG.debug(ex);
+    }
+    catch (Exception ex) {
+      LOG.debug(ex);
+    }
+  }
+
+  @Override
+  public String getEventMessage(final LocatableEvent event) {
+    final Location location = event.location();
+    final String locationQName = location.declaringType().name() + "." + location.method().name();
+    String locationFileName;
+    try {
+      locationFileName = location.sourceName();
+    }
+    catch (AbsentInformationException e) {
+      locationFileName = getSourcePosition().getFile().getName();
+    }
+    final int locationLine = location.lineNumber();
+
+    if (event instanceof ModificationWatchpointEvent) {
+      final ModificationWatchpointEvent modificationEvent = (ModificationWatchpointEvent)event;
+      final ObjectReference object = modificationEvent.object();
+      final Field field = modificationEvent.field();
+      if (object != null) {
+        return DebuggerBundle.message(
+          "status.field.watchpoint.reached.modification", 
+          field.declaringType().name(), 
+          field.name(), 
+          modificationEvent.valueCurrent(), 
+          modificationEvent.valueToBe(),
+          locationQName,
+          locationFileName,
+          locationLine,
+          object.uniqueID()
+        );
+      }
+      return DebuggerBundle.message(
+        "status.static.field.watchpoint.reached.modification", 
+        field.declaringType().name(), 
+        field.name(), 
+        modificationEvent.valueCurrent(), 
+        modificationEvent.valueToBe(),
+        locationQName,
+        locationFileName,
+        locationLine
+      );
+    }
+    if (event instanceof AccessWatchpointEvent) {
+      AccessWatchpointEvent accessEvent = (AccessWatchpointEvent)event;
+      final ObjectReference object = accessEvent.object();
+      final Field field = accessEvent.field();
+      if (object != null) {
+        return DebuggerBundle.message(
+          "status.field.watchpoint.reached.access", 
+          field.declaringType().name(), 
+          field.name(), 
+          locationQName,
+          locationFileName,
+          locationLine,
+          object.uniqueID()
+        );
+      }
+      return DebuggerBundle.message(
+        "status.static.field.watchpoint.reached.access", 
+        field.declaringType().name(), 
+        field.name(),
+        locationQName,
+        locationFileName,
+        locationLine
+      );
+    }
+    return null;
+  }
+
+  @Override
+  public String getDisplayName() {
+    if(!isValid()) {
+      return DebuggerBundle.message("status.breakpoint.invalid");
+    }
+    final String className = getClassName();
+    return className != null && !className.isEmpty() ? className + "." + myFieldName : myFieldName;
+  }
+
+  public static FieldBreakpoint create(@NotNull Project project, @NotNull Document document, int lineIndex, String fieldName) {
+    FieldBreakpoint breakpoint = new FieldBreakpoint(project, createHighlighter(project, document, lineIndex), fieldName);
+    return (FieldBreakpoint)breakpoint.init();
+  }
+
+  @Override
+  public boolean canMoveTo(final SourcePosition position) {
+    return super.canMoveTo(position) && PositionUtil.getPsiElementAt(getProject(), PsiField.class, position) != null;
+  }
+
+  @Override
+  public boolean isValid() {
+    return super.isValid() && getPsiField() != null;
+  }
+
+  @Override
+  public boolean isAt(@NotNull Document document, int offset) {
+    PsiField field = findField(myProject, document, offset);
+    return field == getPsiField();
+  }
+
+  protected static FieldBreakpoint create(@NotNull Project project, @NotNull Field field, ObjectReference object) {
+    String fieldName = field.name();
+    int line = 0;
+    Document document = null;
+    try {
+      List locations = field.declaringType().allLineLocations();
+      if(!locations.isEmpty()) {
+        Location location = (Location)locations.get(0);
+        line = location.lineNumber();
+        VirtualFile file = VirtualFileManager.getInstance().findFileByUrl(location.sourcePath());
+        if(file != null) {
+          PsiFile psiFile = PsiManager.getInstance(project).findFile(file);
+          if(psiFile != null) {
+            document = PsiDocumentManager.getInstance(project).getDocument(psiFile);
+          }
+        }
+      }
+    }
+    catch (AbsentInformationException e) {
+      LOG.debug(e);
+    }
+    catch (InternalError e) {
+      LOG.debug(e);
+    }
+
+    if(document == null) return null;
+
+    FieldBreakpoint fieldBreakpoint = new FieldBreakpoint(project, createHighlighter(project, document, line), fieldName);
+    if (!fieldBreakpoint.isStatic()) {
+      fieldBreakpoint.addInstanceFilter(object.uniqueID());
+    }
+    return (FieldBreakpoint)fieldBreakpoint.init();
+  }
+
+  public static PsiField findField(Project project, Document document, int offset) {
+    PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(document);
+    if(file == null) return null;
+    offset = CharArrayUtil.shiftForward(document.getCharsSequence(), offset, " \t");
+    PsiElement element = file.findElementAt(offset);
+    if(element == null) return null;
+    PsiField field = PsiTreeUtil.getParentOfType(element, PsiField.class, false);
+    int line = document.getLineNumber(offset);
+    if(field == null) {
+      final PsiField[] fld = {null};
+      XDebuggerUtil.getInstance().iterateLine(project, document, line, new Processor<PsiElement>() {
+        @Override
+        public boolean process(PsiElement element) {
+          PsiField field = PsiTreeUtil.getParentOfType(element, PsiField.class, false);
+          if(field != null) {
+            fld[0] = field;
+            return false;
+          }
+          return true;
+        }
+      });
+      field = fld[0];
+    }
+
+    return field;
+  }
+
+  @Override
+  public void readExternal(@NotNull Element breakpointNode) throws InvalidDataException {
+    super.readExternal(breakpointNode);
+    //noinspection HardCodedStringLiteral
+    myFieldName = breakpointNode.getAttributeValue("field_name");
+    if(myFieldName == null) {
+      throw new InvalidDataException("No field name for field breakpoint");
+    }
+  }
+
+  @Override
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  public void writeExternal(@NotNull Element parentNode) throws WriteExternalException {
+    super.writeExternal(parentNode);
+    parentNode.setAttribute("field_name", getFieldName());
+  }
+
+  @Override
+  public PsiElement getEvaluationElement() {
+    return getPsiClass();
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FieldBreakpointFactory.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FieldBreakpointFactory.java
new file mode 100644
index 0000000..496e013
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FieldBreakpointFactory.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.breakpoints;
+
+import com.intellij.CommonBundle;
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.HelpID;
+import com.intellij.debugger.ui.breakpoints.actions.*;
+import com.intellij.icons.AllIcons;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.openapi.ui.Messages;
+import com.intellij.openapi.util.Key;
+import com.intellij.openapi.util.Ref;
+import com.intellij.psi.*;
+import com.intellij.psi.search.GlobalSearchScope;
+import org.jdom.Element;
+
+import javax.swing.*;
+import java.awt.event.ActionEvent;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: Apr 26, 2005
+ */
+public class FieldBreakpointFactory extends BreakpointFactory{
+  public Breakpoint createBreakpoint(Project project, final Element element) {
+    return new FieldBreakpoint(project);
+  }
+
+  public Icon getIcon() {
+    return AllIcons.Debugger.Db_field_breakpoint;
+  }
+
+  public Icon getDisabledIcon() {
+    return AllIcons.Debugger.Db_disabled_field_breakpoint;
+  }
+
+  @Override
+  protected void configureBreakpointPanel(BreakpointPanel panel) {
+    panel.getTree().setGroupByMethods(false);
+  }
+
+  @Override
+  protected String getHelpID() {
+    return HelpID.FIELD_WATCHPOINTS;
+  }
+
+  @Override
+  public String getDisplayName() {
+    return DebuggerBundle.message("field.watchpoints.tab.title");
+  }
+
+  @Override
+  public BreakpointPropertiesPanel createBreakpointPropertiesPanel(Project project, boolean compact) {
+    return new FieldBreakpointPropertiesPanel(project, compact);
+  }
+
+  @Override
+  protected BreakpointPanelAction[] createBreakpointPanelActions(final Project project, final DialogWrapper parentDialog) {
+    return new BreakpointPanelAction[] {
+      new SwitchViewAction(),
+      new AddAction(this, project),
+      new GotoSourceAction(project) {
+        public void actionPerformed(ActionEvent e) {
+          super.actionPerformed(e);
+          parentDialog.close(DialogWrapper.OK_EXIT_CODE);
+        }
+      },
+      new ViewSourceAction(project),
+      new RemoveAction(project),
+      new ToggleGroupByClassesAction(),
+      new ToggleFlattenPackagesAction(),
+    };
+  }
+
+  public Key<FieldBreakpoint> getBreakpointCategory() {
+    return FieldBreakpoint.CATEGORY;
+  }
+
+  @Override
+  public Breakpoint addBreakpoint(final Project project) {
+    final Ref<Breakpoint> result = Ref.create(null);
+    AddFieldBreakpointDialog dialog = new AddFieldBreakpointDialog(project) {
+      protected boolean validateData() {
+        String className = getClassName();
+        if (className.length() == 0) {
+          Messages.showMessageDialog(project, DebuggerBundle.message("error.field.breakpoint.class.name.not.specified"),
+                                     DebuggerBundle.message("add.field.breakpoint.dialog.title"), Messages.getErrorIcon());
+          return false;
+        }
+        String fieldName = getFieldName();
+        if (fieldName.length() == 0) {
+          Messages.showMessageDialog(project, DebuggerBundle.message("error.field.breakpoint.field.name.not.specified"),
+                                     DebuggerBundle.message("add.field.breakpoint.dialog.title"), Messages.getErrorIcon());
+          return false;
+        }
+        PsiClass psiClass = JavaPsiFacade.getInstance(project).findClass(className, GlobalSearchScope.allScope(project));
+        if (psiClass != null) {
+          PsiFile psiFile  = psiClass.getContainingFile();
+          Document document = PsiDocumentManager.getInstance(project).getDocument(psiFile);
+          if(document != null) {
+            PsiField field = psiClass.findFieldByName(fieldName, true);
+            if(field != null) {
+              int line = document.getLineNumber(field.getTextOffset());
+              FieldBreakpoint fieldBreakpoint = DebuggerManagerEx.getInstanceEx(project).getBreakpointManager().addFieldBreakpoint(document, line, fieldName);
+              if (fieldBreakpoint != null) {
+                result.set(fieldBreakpoint);
+                return true;
+              }
+            }
+            else {
+              Messages.showMessageDialog(project,
+                DebuggerBundle.message("error.field.breakpoint.field.not.found", className, fieldName, fieldName),
+                CommonBundle.getErrorTitle(),
+                Messages.getErrorIcon()
+              );
+            }
+          }
+        } else {
+          Messages.showMessageDialog(project,
+            DebuggerBundle.message("error.field.breakpoint.class.sources.not.found", className, fieldName, className),
+            CommonBundle.getErrorTitle(),
+            Messages.getErrorIcon()
+          );
+        }
+        return false;
+      }
+    };
+    dialog.show();
+    return result.get();
+  }
+
+  @Override
+  public boolean canAddBreakpoints() {
+    return true;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FieldBreakpointPropertiesPanel.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FieldBreakpointPropertiesPanel.java
new file mode 100644
index 0000000..77497f7
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FieldBreakpointPropertiesPanel.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/**
+ * class FieldBreakpointPropertiesPanel
+ * @author Jeka
+ */
+package com.intellij.debugger.ui.breakpoints;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.openapi.project.Project;
+import com.intellij.ui.IdeBorderFactory;
+import com.intellij.util.ui.DialogUtil;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+public class FieldBreakpointPropertiesPanel extends BreakpointPropertiesPanel {
+  private JCheckBox myWatchAccessCheckBox;
+  private JCheckBox myWatchModificationCheckBox;
+
+  public FieldBreakpointPropertiesPanel(final Project project, boolean compact) {
+    super(project, FieldBreakpoint.CATEGORY, compact);
+  }
+
+  protected JComponent createSpecialBox() {
+    JPanel _panel;
+    JPanel _panel0;
+    myWatchAccessCheckBox = new JCheckBox(DebuggerBundle.message("label.filed.breakpoint.properties.panel.field.access"));
+    myWatchModificationCheckBox = new JCheckBox(DebuggerBundle.message("label.filed.breakpoint.properties.panel.field.modification"));
+    DialogUtil.registerMnemonic(myWatchAccessCheckBox);
+    DialogUtil.registerMnemonic(myWatchModificationCheckBox);
+
+
+    Box watchBox = Box.createVerticalBox();
+    _panel = new JPanel(new BorderLayout());
+    _panel.add(myWatchAccessCheckBox, BorderLayout.NORTH);
+    watchBox.add(_panel);
+    _panel = new JPanel(new BorderLayout());
+    _panel.add(myWatchModificationCheckBox, BorderLayout.NORTH);
+    watchBox.add(_panel);
+
+    _panel = new JPanel(new BorderLayout());
+    _panel0 = new JPanel(new BorderLayout());
+    _panel0.add(watchBox, BorderLayout.CENTER);
+    _panel0.add(Box.createHorizontalStrut(3), BorderLayout.WEST);
+    _panel0.add(Box.createHorizontalStrut(3), BorderLayout.EAST);
+    _panel.add(_panel0, BorderLayout.NORTH);
+    _panel.setBorder(IdeBorderFactory.createTitledBorder(DebuggerBundle.message("label.group.watch.events"), true));
+
+    ActionListener listener = new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        JCheckBox toCheck = null;
+        if (!myWatchAccessCheckBox.isSelected() && !myWatchModificationCheckBox.isSelected()) {
+          Object source = e.getSource();
+          if (myWatchAccessCheckBox.equals(source)) {
+            toCheck = myWatchModificationCheckBox;
+          }
+          else if (myWatchModificationCheckBox.equals(source)) {
+            toCheck = myWatchAccessCheckBox;
+          }
+          if (toCheck != null) {
+            toCheck.setSelected(true);
+          }
+        }
+      }
+    };
+    myWatchAccessCheckBox.addActionListener(listener);
+    myWatchModificationCheckBox.addActionListener(listener);
+
+    return _panel;
+  }
+
+  public void initFrom(Breakpoint breakpoint, boolean moreOptionsVisible) {
+    super.initFrom(breakpoint, moreOptionsVisible);
+    FieldBreakpoint fieldBreakpoint = (FieldBreakpoint)breakpoint;
+
+    myWatchAccessCheckBox.setSelected(fieldBreakpoint.WATCH_ACCESS);
+    myWatchModificationCheckBox.setSelected(fieldBreakpoint.WATCH_MODIFICATION);
+  }
+
+  public void saveTo(Breakpoint breakpoint, @NotNull Runnable afterUpdate) {
+    FieldBreakpoint fieldBreakpoint = (FieldBreakpoint)breakpoint;
+
+    fieldBreakpoint.WATCH_ACCESS = myWatchAccessCheckBox.isSelected();
+    fieldBreakpoint.WATCH_MODIFICATION = myWatchModificationCheckBox.isSelected();
+
+    super.saveTo(breakpoint, afterUpdate);
+  }
+}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FilteredRequestor.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FilteredRequestor.java
new file mode 100644
index 0000000..e8fd23e
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/FilteredRequestor.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/**
+ * class FilteredRequestor
+ * @author Jeka
+ */
+package com.intellij.debugger.ui.breakpoints;
+
+import com.intellij.debugger.*;
+import com.intellij.debugger.engine.ContextUtil;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.evaluation.*;
+import com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilderImpl;
+import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator;
+import com.intellij.debugger.engine.requests.LocatableEventRequestor;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.settings.DebuggerSettings;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.*;
+import com.intellij.psi.PsiElement;
+import com.intellij.ui.classFilter.ClassFilter;
+import com.sun.jdi.BooleanValue;
+import com.sun.jdi.ObjectReference;
+import com.sun.jdi.VMDisconnectedException;
+import com.sun.jdi.Value;
+import com.sun.jdi.event.LocatableEvent;
+import org.jdom.Element;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public abstract class FilteredRequestor implements LocatableEventRequestor, JDOMExternalizable {
+
+  public String  SUSPEND_POLICY = DebuggerSettings.SUSPEND_ALL;
+  public boolean  SUSPEND = true;
+
+  public boolean COUNT_FILTER_ENABLED     = false;
+  public int COUNT_FILTER = 0;
+
+  public boolean CONDITION_ENABLED        = false;
+  private TextWithImports myCondition;
+
+  public boolean CLASS_FILTERS_ENABLED    = false;
+  private ClassFilter[] myClassFilters          = ClassFilter.EMPTY_ARRAY;
+  private ClassFilter[] myClassExclusionFilters = ClassFilter.EMPTY_ARRAY;
+
+  public boolean INSTANCE_FILTERS_ENABLED = false;
+  private InstanceFilter[] myInstanceFilters  = InstanceFilter.EMPTY_ARRAY;
+
+  @NonNls private static final String FILTER_OPTION_NAME = "filter";
+  @NonNls private static final String EXCLUSION_FILTER_OPTION_NAME = "exclusion_filter";
+  @NonNls private static final String INSTANCE_ID_OPTION_NAME = "instance_id";
+  @NonNls private static final String CONDITION_OPTION_NAME = "CONDITION";
+  protected final Project myProject;
+
+  public FilteredRequestor(@NotNull Project project) {
+    myProject = project;
+    myCondition = new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, "");
+  }
+
+  public InstanceFilter[] getInstanceFilters() {
+    return myInstanceFilters;
+  }
+
+  public void setInstanceFilters(InstanceFilter[] instanceFilters) {
+    myInstanceFilters = instanceFilters != null? instanceFilters : InstanceFilter.EMPTY_ARRAY;
+  }
+
+  public String getSuspendPolicy() {
+    return SUSPEND? SUSPEND_POLICY : DebuggerSettings.SUSPEND_NONE;
+  }
+
+  /**
+   * @return true if the ID was added or false otherwise
+   */
+  private boolean hasObjectID(long id) {
+    for (InstanceFilter instanceFilter : myInstanceFilters) {
+      if (instanceFilter.getId() == id) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  protected void addInstanceFilter(long l) {
+    final InstanceFilter[] filters = new InstanceFilter[myInstanceFilters.length + 1];
+    System.arraycopy(myInstanceFilters, 0, filters, 0, myInstanceFilters.length);
+    filters[myInstanceFilters.length] = InstanceFilter.create(String.valueOf(l));
+    myInstanceFilters = filters;
+  }
+
+  public final ClassFilter[] getClassFilters() {
+    return myClassFilters;
+  }
+
+  public final void setClassFilters(ClassFilter[] classFilters) {
+    myClassFilters = classFilters != null? classFilters : ClassFilter.EMPTY_ARRAY;
+  }
+
+  public ClassFilter[] getClassExclusionFilters() {
+    return myClassExclusionFilters;
+  }
+
+  public void setClassExclusionFilters(ClassFilter[] classExclusionFilters) {
+    myClassExclusionFilters = classExclusionFilters != null? classExclusionFilters : ClassFilter.EMPTY_ARRAY;
+  }
+
+  public void readExternal(Element parentNode) throws InvalidDataException {
+    DefaultJDOMExternalizer.readExternal(this, parentNode);
+    if (DebuggerSettings.SUSPEND_NONE.equals(SUSPEND_POLICY)) { // compatibility with older format
+      SUSPEND = false;
+      SUSPEND_POLICY = DebuggerSettings.SUSPEND_ALL;
+    }
+    String condition = JDOMExternalizerUtil.readField(parentNode, CONDITION_OPTION_NAME);
+    if (condition != null) {
+      setCondition(new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, condition));
+    }
+
+    myClassFilters = DebuggerUtilsEx.readFilters(parentNode.getChildren(FILTER_OPTION_NAME));
+    myClassExclusionFilters = DebuggerUtilsEx.readFilters(parentNode.getChildren(EXCLUSION_FILTER_OPTION_NAME));
+
+    final ClassFilter [] instanceFilters = DebuggerUtilsEx.readFilters(parentNode.getChildren(INSTANCE_ID_OPTION_NAME));
+    final List<InstanceFilter> iFilters = new ArrayList<InstanceFilter>(instanceFilters.length);
+
+    for (ClassFilter instanceFilter : instanceFilters) {
+      try {
+        iFilters.add(InstanceFilter.create(instanceFilter));
+      }
+      catch (Exception e) {
+      }
+    }
+    myInstanceFilters = iFilters.isEmpty() ? InstanceFilter.EMPTY_ARRAY : iFilters.toArray(new InstanceFilter[iFilters.size()]);
+  }
+
+  public void writeExternal(Element parentNode) throws WriteExternalException {
+    DefaultJDOMExternalizer.writeExternal(this, parentNode);
+    JDOMExternalizerUtil.writeField(parentNode, CONDITION_OPTION_NAME, getCondition().toExternalForm());
+    DebuggerUtilsEx.writeFilters(parentNode, FILTER_OPTION_NAME, myClassFilters);
+    DebuggerUtilsEx.writeFilters(parentNode, EXCLUSION_FILTER_OPTION_NAME, myClassExclusionFilters);
+    DebuggerUtilsEx.writeFilters(parentNode, INSTANCE_ID_OPTION_NAME, InstanceFilter.createClassFilters(myInstanceFilters));
+  }
+
+  public boolean evaluateCondition(final EvaluationContextImpl context, LocatableEvent event) throws EvaluateException {
+    if(COUNT_FILTER_ENABLED) {
+      final DebugProcessImpl debugProcess = context.getDebugProcess();
+      debugProcess.getVirtualMachineProxy().suspend();
+      debugProcess.getRequestsManager().deleteRequest(this);
+      ((Breakpoint)this).createRequest(debugProcess);
+      debugProcess.getVirtualMachineProxy().resume();
+    }
+    if (INSTANCE_FILTERS_ENABLED) {
+      Value value = context.getThisObject();
+      if (value != null) {  // non-static
+        ObjectReference reference = (ObjectReference)value;
+        if(!hasObjectID(reference.uniqueID())) {
+          return false;
+        }
+      }
+    }
+
+    if (CONDITION_ENABLED && getCondition() != null && !"".equals(getCondition().getText())) {
+      try {
+        ExpressionEvaluator evaluator = DebuggerInvocationUtil.commitAndRunReadAction(context.getProject(), new EvaluatingComputable<ExpressionEvaluator>() {
+          public ExpressionEvaluator compute() throws EvaluateException {
+            final SourcePosition contextSourcePosition = ContextUtil.getSourcePosition(context);
+            // IMPORTANT: calculate context psi element basing on the location where the exception
+            // has been hit, not on the location where it was set. (For line breakpoints these locations are the same, however, 
+            // for method, exception and field breakpoints these locations differ)
+            PsiElement contextPsiElement = ContextUtil.getContextElement(contextSourcePosition);
+            if (contextPsiElement == null) {
+              contextPsiElement = getEvaluationElement(); // as a last resort
+            }
+            return EvaluatorBuilderImpl.build(getCondition(), contextPsiElement, contextSourcePosition);
+          }
+        });
+        final Value value = evaluator.evaluate(context);
+        if (!(value instanceof BooleanValue)) {
+          throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.boolean.expected"));
+        }
+        if(!((BooleanValue)value).booleanValue()) {
+          return false;
+        }
+      }
+      catch (EvaluateException ex) {
+        if(ex.getCause() instanceof VMDisconnectedException) {
+          return false;
+        }
+        throw EvaluateExceptionUtil.createEvaluateException(
+          DebuggerBundle.message("error.failed.evaluating.breakpoint.condition", getCondition(), ex.getMessage())
+        );
+      }
+      return true;
+    }
+
+    return true;
+  }
+
+  public abstract PsiElement getEvaluationElement();
+
+  public TextWithImports getCondition() {
+    return myCondition;
+  }
+
+  public void setCondition(TextWithImports condition) {
+    myCondition = condition;
+  }
+
+  public Project getProject() {
+    return myProject;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaBreakpointItem.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaBreakpointItem.java
new file mode 100644
index 0000000..d37ae54
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaBreakpointItem.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2000-2012 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.debugger.ui.breakpoints;
+
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.SourcePosition;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.ui.SimpleColoredComponent;
+import com.intellij.ui.SimpleTextAttributes;
+import com.intellij.ui.popup.util.DetailView;
+import com.intellij.xdebugger.impl.breakpoints.ui.BreakpointItem;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+
+class JavaBreakpointItem extends BreakpointItem {
+  private final Breakpoint myBreakpoint;
+  private BreakpointFactory myBreakpointFactory;
+
+  public JavaBreakpointItem(@Nullable BreakpointFactory breakpointFactory, Breakpoint breakpoint) {
+    myBreakpointFactory = breakpointFactory;
+    myBreakpoint = breakpoint;
+  }
+
+  @Override
+  protected void setupGenericRenderer(SimpleColoredComponent renderer, boolean plainView) {
+    if (plainView) {
+      renderer.setIcon(myBreakpoint.getIcon());
+    }
+    renderer.append(plainView ? StringUtil.shortenTextWithEllipsis(myBreakpoint.getShortName(), 60, 0) : myBreakpoint.getDisplayName(),
+                    isEnabled() ? SimpleTextAttributes.REGULAR_ATTRIBUTES : SimpleTextAttributes.GRAY_ATTRIBUTES);
+  }
+
+  @Override
+  public Icon getIcon() {
+    return myBreakpoint.getIcon();
+  }
+
+  @Override
+  public String getDisplayText() {
+    return myBreakpoint.getDisplayName();
+  }
+
+  @Override
+  public String speedSearchText() {
+    return myBreakpoint.getDisplayName();
+  }
+
+  @Override
+  public String footerText() {
+    return myBreakpoint.getDisplayName();
+  }
+
+  @Override
+  protected void doUpdateDetailView(DetailView panel, boolean editorOnly) {
+    BreakpointPropertiesPanel breakpointPropertiesPanel = null;
+    if (!editorOnly) {
+      breakpointPropertiesPanel = myBreakpointFactory != null ? myBreakpointFactory
+        .createBreakpointPropertiesPanel(myBreakpoint.getProject(), false) : null;
+
+      if (breakpointPropertiesPanel != null) {
+        breakpointPropertiesPanel.initFrom(myBreakpoint, true);
+
+        breakpointPropertiesPanel.setSaveOnRemove(true);
+
+        final JPanel mainPanel = breakpointPropertiesPanel.getPanel();
+        panel.setPropertiesPanel(mainPanel);
+      }
+      else {
+        panel.setPropertiesPanel(null);
+      }
+    }
+
+    if (myBreakpoint instanceof BreakpointWithHighlighter) {
+      SourcePosition sourcePosition = ((BreakpointWithHighlighter)myBreakpoint).getSourcePosition();
+      VirtualFile virtualFile = sourcePosition.getFile().getVirtualFile();
+      showInEditor(panel, virtualFile, sourcePosition.getLine());
+    } else {
+      panel.clearEditor();
+    }
+    if (breakpointPropertiesPanel != null) {
+      breakpointPropertiesPanel.setDetailView(panel);
+    }
+  }
+
+  @Override
+  public boolean navigate() {
+    if (myBreakpoint instanceof BreakpointWithHighlighter) {
+      ((BreakpointWithHighlighter)myBreakpoint).getSourcePosition().navigate(true);
+      return true;
+    }
+    return false;
+  }
+
+  @Override
+  public boolean allowedToRemove() {
+    return myBreakpointFactory != null && myBreakpointFactory.breakpointCanBeRemoved(myBreakpoint);
+  }
+
+  @Override
+  public void removed(Project project) {
+    DebuggerManagerEx.getInstanceEx(project).getBreakpointManager().removeBreakpoint(myBreakpoint);
+  }
+
+  @Override
+  public Object getBreakpoint() {
+    return myBreakpoint;
+  }
+
+  @Override
+  public boolean isEnabled() {
+    return myBreakpoint.ENABLED;
+  }
+
+  @Override
+  public void setEnabled(boolean state) {
+    myBreakpoint.ENABLED = state;
+  }
+
+  @Override
+  public boolean isDefaultBreakpoint() {
+    return myBreakpoint.getCategory().equals(AnyExceptionBreakpoint.CATEGORY);
+  }
+
+  @Override
+  public int compareTo(BreakpointItem breakpointItem) {
+    final Object breakpoint = breakpointItem.getBreakpoint();
+    if (breakpoint instanceof Breakpoint) {
+      return -getIndexOf(myBreakpoint) + getIndexOf((Breakpoint)breakpoint);
+    }
+    return getDisplayText().compareTo(breakpointItem.getDisplayText());
+  }
+
+  private int getIndexOf(Breakpoint breakpoint) {
+    return DebuggerManagerEx.getInstanceEx(myBreakpoint.getProject()).getBreakpointManager().getBreakpoints().indexOf(breakpoint);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpoint.java
new file mode 100644
index 0000000..de3b918
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpoint.java
@@ -0,0 +1,464 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class LineBreakpoint
+ * @author Jeka
+ */
+package com.intellij.debugger.ui.breakpoints;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.SourcePosition;
+import com.intellij.debugger.actions.ThreadDumpAction;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.impl.PositionUtil;
+import com.intellij.debugger.jdi.StackFrameProxyImpl;
+import com.intellij.icons.AllIcons;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.markup.RangeHighlighter;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.ProjectFileIndex;
+import com.intellij.openapi.roots.ProjectRootManager;
+import com.intellij.openapi.util.Computable;
+import com.intellij.openapi.util.Key;
+import com.intellij.openapi.util.registry.Registry;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.*;
+import com.intellij.psi.jsp.JspFile;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.ui.classFilter.ClassFilter;
+import com.intellij.util.Processor;
+import com.intellij.util.StringBuilderSpinAllocator;
+import com.intellij.xdebugger.XDebuggerUtil;
+import com.sun.jdi.*;
+import com.sun.jdi.event.LocatableEvent;
+import com.sun.jdi.request.BreakpointRequest;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+public class LineBreakpoint extends BreakpointWithHighlighter {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.breakpoints.LineBreakpoint");
+
+  private String myMethodName;
+  public static final @NonNls Key<LineBreakpoint> CATEGORY = BreakpointCategory.lookup("line_breakpoints");
+
+  protected LineBreakpoint(Project project) {
+    super(project);
+  }
+
+  protected LineBreakpoint(Project project, RangeHighlighter highlighter) {
+    super(project, highlighter);
+  }
+
+  protected Icon getDisabledIcon(boolean isMuted) {
+    final Breakpoint master = DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager().findMasterBreakpoint(this);
+    if (isMuted) {
+      return master == null? AllIcons.Debugger.Db_muted_disabled_breakpoint : AllIcons.Debugger.Db_muted_dep_line_breakpoint;
+    }
+    else {
+      return master == null? AllIcons.Debugger.Db_disabled_breakpoint : AllIcons.Debugger.Db_dep_line_breakpoint;
+    }
+  }
+
+  protected Icon getSetIcon(boolean isMuted) {
+    return isMuted? AllIcons.Debugger.Db_muted_breakpoint : AllIcons.Debugger.Db_set_breakpoint;
+  }
+
+  protected Icon getInvalidIcon(boolean isMuted) {
+    return isMuted? AllIcons.Debugger.Db_muted_invalid_breakpoint : AllIcons.Debugger.Db_invalid_breakpoint;
+  }
+
+  protected Icon getVerifiedIcon(boolean isMuted) {
+    return isMuted? AllIcons.Debugger.Db_muted_verified_breakpoint : AllIcons.Debugger.Db_verified_breakpoint;
+  }
+
+  protected Icon getVerifiedWarningsIcon(boolean isMuted) {
+    return isMuted? AllIcons.Debugger.Db_muted_verified_warning_breakpoint : AllIcons.Debugger.Db_verified_warning_breakpoint;
+  }
+
+  public Key<LineBreakpoint> getCategory() {
+    return CATEGORY;
+  }
+
+  protected void reload(PsiFile file) {
+    super.reload(file);
+    myMethodName = findMethodName(file, getHighlighter().getStartOffset());
+  }
+
+  protected void createOrWaitPrepare(DebugProcessImpl debugProcess, String classToBeLoaded) {
+    if (isInScopeOf(debugProcess, classToBeLoaded)) {
+      super.createOrWaitPrepare(debugProcess, classToBeLoaded);
+    }
+  }
+
+  protected void createRequestForPreparedClass(final DebugProcessImpl debugProcess, final ReferenceType classType) {
+    if (!isInScopeOf(debugProcess, classType.name())) {
+      return;
+    }
+    try {
+      List<Location> locs = debugProcess.getPositionManager().locationsOfLine(classType, getSourcePosition());
+      if (!locs.isEmpty()) {
+        for (Location loc : locs) {
+          if (LOG.isDebugEnabled()) {
+            LOG.debug("Found location [codeIndex=" + loc.codeIndex() +"] for reference type " + classType.name() + " at line " + getLineIndex() + "; isObsolete: " + (debugProcess.getVirtualMachineProxy().versionHigher("1.4") && loc.method().isObsolete()));
+          }
+          BreakpointRequest request = debugProcess.getRequestsManager().createBreakpointRequest(LineBreakpoint.this, loc);
+          debugProcess.getRequestsManager().enableRequest(request);
+          if (LOG.isDebugEnabled()) {
+            LOG.debug("Created breakpoint request for reference type " + classType.name() + " at line " + getLineIndex() + "; codeIndex=" + loc.codeIndex());
+          }
+        }
+      }
+      else {
+        // there's no executable code in this class
+        debugProcess.getRequestsManager().setInvalid(LineBreakpoint.this, DebuggerBundle.message(
+          "error.invalid.breakpoint.no.executable.code", (getLineIndex() + 1), classType.name())
+        );
+        if (LOG.isDebugEnabled()) {
+          LOG.debug("No locations of type " + classType.name() + " found at line " + getLineIndex());
+        }
+      }
+    }
+    catch (ClassNotPreparedException ex) {
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("ClassNotPreparedException: " + ex.getMessage());
+      }
+      // there's a chance to add a breakpoint when the class is prepared
+    }
+    catch (ObjectCollectedException ex) {
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("ObjectCollectedException: " + ex.getMessage());
+      }
+      // there's a chance to add a breakpoint when the class is prepared
+    }
+    catch (InvalidLineNumberException ex) {
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("InvalidLineNumberException: " + ex.getMessage());
+      }
+      debugProcess.getRequestsManager().setInvalid(LineBreakpoint.this, DebuggerBundle.message("error.invalid.breakpoint.bad.line.number"));
+    }
+    catch (InternalException ex) {
+      LOG.info(ex);
+    }
+    catch(Exception ex) {
+      LOG.info(ex);
+    }
+    updateUI();
+  }
+
+  private boolean isInScopeOf(DebugProcessImpl debugProcess, String className) {
+    final SourcePosition position = getSourcePosition();
+    if (position != null) {
+      final VirtualFile breakpointFile = position.getFile().getVirtualFile();
+      final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(myProject).getFileIndex();
+      if (breakpointFile != null && fileIndex.isInSourceContent(breakpointFile)) {
+        // apply filtering to breakpoints from content sources only, not for sources attached to libraries
+        final Collection<VirtualFile> candidates = findClassCandidatesInSourceContent(className, debugProcess.getSearchScope(), fileIndex);
+        if (candidates == null) {
+          return true;
+        }
+        for (VirtualFile classFile : candidates) {
+          if (breakpointFile.equals(classFile)) {
+            return true;
+          }
+        }
+        return false;
+      }
+    }
+    return true;
+  }
+
+  @Nullable
+  private Collection<VirtualFile> findClassCandidatesInSourceContent(final String className, final GlobalSearchScope scope, final ProjectFileIndex fileIndex) {
+    final int dollarIndex = className.indexOf("$");
+    final String topLevelClassName = dollarIndex >= 0? className.substring(0, dollarIndex) : className;
+    return ApplicationManager.getApplication().runReadAction(new Computable<Collection<VirtualFile>>() {
+      @Nullable
+      public Collection<VirtualFile> compute() {
+        final PsiClass[] classes = JavaPsiFacade.getInstance(myProject).findClasses(topLevelClassName, scope);
+        if (classes.length == 0) {
+          return null;
+        }
+        final List<VirtualFile> list = new ArrayList<VirtualFile>(classes.length);
+        for (PsiClass aClass : classes) {
+          final PsiFile psiFile = aClass.getContainingFile();
+          if (psiFile != null) {
+            final VirtualFile vFile = psiFile.getVirtualFile();
+            if (vFile != null && fileIndex.isInSourceContent(vFile)) {
+              list.add(vFile);
+            }
+          }
+        }
+        return list;
+      }
+    });
+  }
+
+  public boolean evaluateCondition(EvaluationContextImpl context, LocatableEvent event) throws EvaluateException {
+    if(CLASS_FILTERS_ENABLED){
+      String className = null;
+      final ObjectReference thisObject = (ObjectReference)context.getThisObject();
+      if(thisObject != null) {
+        className = thisObject.referenceType().name();
+      }
+      else {
+        final StackFrameProxyImpl frame = context.getFrameProxy();
+        if (frame != null) {
+          className = frame.location().declaringType().name();
+        }
+      }
+      if (className != null) {
+        boolean matches = false;
+        for (ClassFilter classFilter : getClassFilters()) {
+          if (classFilter.isEnabled() && classFilter.matches(className)) {
+            matches = true;
+            break;
+          }
+        }
+        if(!matches) {
+          return false;
+        }
+        for (ClassFilter classFilter : getClassExclusionFilters()) {
+          if (classFilter.isEnabled() && classFilter.matches(className)) {
+            return false;
+          }
+        }
+      }
+    }
+    return super.evaluateCondition(context, event);
+  }
+
+  public String toString() {
+    return getDescription();
+  }
+
+  @Override
+  public String getShortName() {
+    return getDisplayInfoInternal(false, 30);
+  }
+
+  public String getDisplayName() {
+    return getDisplayInfoInternal(true, -1);
+  }
+
+  private String getDisplayInfoInternal(boolean showPackageInfo, int totalTextLength) {
+    final RangeHighlighter highlighter = getHighlighter();
+    if(highlighter.isValid() && isValid()) {
+      final int lineNumber = (highlighter.getDocument().getLineNumber(highlighter.getStartOffset()) + 1);
+      String className = getClassName();
+      final boolean hasClassInfo = className != null && className.length() > 0;
+      final boolean hasMethodInfo = myMethodName != null && myMethodName.length() > 0;
+      if (hasClassInfo || hasMethodInfo) {
+        final StringBuilder info = StringBuilderSpinAllocator.alloc();
+        try {
+          boolean isFile = getSourcePosition().getFile().getName().equals(className);
+          String packageName = null;
+          if (hasClassInfo) {
+            final int dotIndex = className.lastIndexOf(".");
+            if (dotIndex >= 0 && !isFile) {
+              packageName = className.substring(0, dotIndex);
+              className = className.substring(dotIndex + 1); 
+            }
+
+            if (totalTextLength != -1) {
+              if (className.length() + (hasMethodInfo ? myMethodName.length() : 0) > totalTextLength + 3) {
+                int offset = totalTextLength - (hasMethodInfo ? myMethodName.length() : 0);
+                if (offset > 0 && offset < className.length()) {
+                  className = className.substring(className.length() - offset);
+                  info.append("...");
+                }
+              }
+            }
+            
+            info.append(className);
+          }
+          if(hasMethodInfo) {
+            if (isFile) {
+              info.append(":");
+            }
+            else if (hasClassInfo) {
+              info.append(".");
+            }
+            info.append(myMethodName);
+          }
+          if (showPackageInfo && packageName != null) {
+            info.append(" (").append(packageName).append(")");
+          }
+          return DebuggerBundle.message("line.breakpoint.display.name.with.class.or.method", lineNumber, info.toString());
+        }
+        finally {
+          StringBuilderSpinAllocator.dispose(info);
+        }
+      }
+      return DebuggerBundle.message("line.breakpoint.display.name", lineNumber);
+    }
+    return DebuggerBundle.message("status.breakpoint.invalid");
+  }
+
+  private static @Nullable String findMethodName(final PsiFile file, final int offset) {
+    if (file instanceof JspFile) {
+      return null;
+    }
+    if (file instanceof PsiClassOwner) {
+      return ApplicationManager.getApplication().runReadAction(new Computable<String>() {
+        public String compute() {
+          final PsiMethod method = DebuggerUtilsEx.findPsiMethod(file, offset);
+          return method != null? method.getName() + "()" : null;
+        }
+      });
+    }
+    return null;
+  }
+
+  public String getEventMessage(LocatableEvent event) {
+    final Location location = event.location();
+    String sourceName = "Unknown Source";
+    try {
+      sourceName = location.sourceName();
+    }
+    catch (AbsentInformationException e) {
+      sourceName = getSourcePosition().getFile().getName();
+    }
+
+    final boolean printFullTrace = Registry.is("debugger.breakpoint.message.full.trace");
+
+    StringBuilder builder = new StringBuilder();
+    if (printFullTrace) {
+      builder.append(DebuggerBundle.message(
+        "status.line.breakpoint.reached.full.trace",
+        location.declaringType().name() + "." + location.method().name())
+      );
+      try {
+        final List<StackFrame> frames = event.thread().frames();
+        renderTrace(frames, builder);
+      }
+      catch (IncompatibleThreadStateException e) {
+        builder.append("Stacktrace not available: ").append(e.getMessage());
+      }
+    }
+    else {
+      builder.append(DebuggerBundle.message(
+        "status.line.breakpoint.reached",
+        location.declaringType().name() + "." + location.method().name(),
+        sourceName,
+        getLineIndex() + 1
+      ));
+    }
+    return builder.toString();
+  }
+
+  private static void renderTrace(List<StackFrame> frames, StringBuilder buffer) {
+    for (final StackFrame stackFrame : frames) {
+      final Location location = stackFrame.location();
+      buffer.append("\n\t  ").append(ThreadDumpAction.renderLocation(location));
+    }
+  }
+
+  public PsiElement getEvaluationElement() {
+    return PositionUtil.getContextElement(getSourcePosition());
+  }
+
+  protected static LineBreakpoint create(Project project, Document document, int lineIndex) {
+    VirtualFile virtualFile = FileDocumentManager.getInstance().getFile(document);
+    if (virtualFile == null) {
+      return null;
+    }
+
+    final RangeHighlighter highlighter = createHighlighter(project, document, lineIndex);
+    if (highlighter == null) {
+      return null;
+    }
+
+    LineBreakpoint breakpoint = new LineBreakpoint(project, highlighter);
+    return (LineBreakpoint)breakpoint.init();
+  }
+
+  public boolean canMoveTo(SourcePosition position) {
+    if (!super.canMoveTo(position)) {
+      return false;
+    }
+    final Document document = PsiDocumentManager.getInstance(getProject()).getDocument(position.getFile());
+    return canAddLineBreakpoint(myProject, document, position.getLine());
+  }
+
+  public static boolean canAddLineBreakpoint(Project project, final Document document, final int lineIndex) {
+    if (lineIndex < 0 || lineIndex >= document.getLineCount()) {
+      return false;
+    }
+    final BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(project).getBreakpointManager();
+    final LineBreakpoint breakpointAtLine = breakpointManager.findBreakpoint( document, document.getLineStartOffset(lineIndex), CATEGORY);
+    if (breakpointAtLine != null) {
+      // there already exists a line breakpoint at this line
+      return false;
+    }
+    PsiDocumentManager.getInstance(project).commitDocument(document);
+
+    final boolean[] canAdd = new boolean[]{false};
+    XDebuggerUtil.getInstance().iterateLine(project, document, lineIndex, new Processor<PsiElement>() {
+      public boolean process(PsiElement element) {
+        if ((element instanceof PsiWhiteSpace) || (PsiTreeUtil.getParentOfType(element, PsiComment.class, false) != null)) {
+          return true;
+        }
+        PsiElement child = element;
+        while(element != null) {
+
+          final int offset = element.getTextOffset();
+          if (offset >= 0) {
+            if (document.getLineNumber(offset) != lineIndex) {
+              break;
+            }
+          }
+          child = element;
+          element = element.getParent();
+        }
+
+        if(child instanceof PsiMethod && child.getTextRange().getEndOffset() >= document.getLineEndOffset(lineIndex)) {
+          PsiCodeBlock body = ((PsiMethod)child).getBody();
+          if(body == null) {
+            canAdd[0] = false;
+          }
+          else {
+            PsiStatement[] statements = body.getStatements();
+            canAdd[0] = statements.length > 0 && document.getLineNumber(statements[0].getTextOffset()) == lineIndex;
+          }
+        }
+        else {
+          canAdd[0] = true;
+        }
+        return false;
+      }
+    });
+
+    return canAdd[0];
+  }
+
+  public @Nullable String getMethodName() {
+    return myMethodName;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpointFactory.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpointFactory.java
new file mode 100644
index 0000000..dede7de
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpointFactory.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.breakpoints;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.HelpID;
+import com.intellij.debugger.ui.breakpoints.actions.*;
+import com.intellij.icons.AllIcons;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.openapi.util.Key;
+import org.jdom.Element;
+
+import javax.swing.*;
+import java.awt.event.ActionEvent;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: Apr 26, 2005
+ */
+public class LineBreakpointFactory extends BreakpointFactory {
+  public Breakpoint createBreakpoint(Project project, final Element element) {
+    return new LineBreakpoint(project);
+  }
+
+  public Icon getIcon() {
+    return AllIcons.Debugger.Db_set_breakpoint;
+  }
+
+  public Icon getDisabledIcon() {
+    return AllIcons.Debugger.Db_disabled_breakpoint;
+  }
+
+  @Override
+  protected String getHelpID() {
+    return HelpID.LINE_BREAKPOINTS;
+  }
+
+  @Override
+  public String getDisplayName() {
+    return DebuggerBundle.message("line.breakpoints.tab.title");
+  }
+
+  @Override
+  public BreakpointPropertiesPanel createBreakpointPropertiesPanel(Project project, boolean compact) {
+    return new LineBreakpointPropertiesPanel(project, compact);
+  }
+
+  @Override
+  protected BreakpointPanelAction[] createBreakpointPanelActions(Project project, final DialogWrapper parentDialog) {
+    return new BreakpointPanelAction[]{new SwitchViewAction(),
+      new GotoSourceAction(project) {
+        public void actionPerformed(ActionEvent e) {
+          super.actionPerformed(e);
+          parentDialog.close(DialogWrapper.OK_EXIT_CODE);
+        }
+      },
+      new ViewSourceAction(project),
+      new RemoveAction(project),
+      new ToggleGroupByMethodsAction(),
+      new ToggleGroupByClassesAction(),
+      new ToggleFlattenPackagesAction(),
+    };
+  }
+
+  public Key<LineBreakpoint> getBreakpointCategory() {
+    return LineBreakpoint.CATEGORY;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpointPropertiesPanel.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpointPropertiesPanel.java
new file mode 100644
index 0000000..802657b
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpointPropertiesPanel.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class LineBreakpointPropertiesPanel
+ * @author Jeka
+ */
+package com.intellij.debugger.ui.breakpoints;
+
+import com.intellij.openapi.project.Project;
+
+public class LineBreakpointPropertiesPanel extends BreakpointPropertiesPanel {
+  public LineBreakpointPropertiesPanel(Project project, boolean compact) {
+    super(project, LineBreakpoint.CATEGORY, compact);
+  }
+}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpoint.java
new file mode 100644
index 0000000..4cc4eb0
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpoint.java
@@ -0,0 +1,383 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class MethodBreakpoint
+ * @author Jeka
+ */
+package com.intellij.debugger.ui.breakpoints;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.SourcePosition;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.JVMName;
+import com.intellij.debugger.engine.JVMNameUtil;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.engine.requests.RequestManagerImpl;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.impl.PositionUtil;
+import com.intellij.icons.AllIcons;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.markup.RangeHighlighter;
+import com.intellij.openapi.project.IndexNotReadyException;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Computable;
+import com.intellij.openapi.util.Key;
+import com.intellij.psi.*;
+import com.intellij.util.StringBuilderSpinAllocator;
+import com.intellij.util.text.CharArrayUtil;
+import com.sun.jdi.AbsentInformationException;
+import com.sun.jdi.Location;
+import com.sun.jdi.Method;
+import com.sun.jdi.ReferenceType;
+import com.sun.jdi.event.LocatableEvent;
+import com.sun.jdi.event.MethodEntryEvent;
+import com.sun.jdi.event.MethodExitEvent;
+import com.sun.jdi.request.EventRequest;
+import com.sun.jdi.request.MethodEntryRequest;
+import com.sun.jdi.request.MethodExitRequest;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.util.Iterator;
+import java.util.Set;
+
+public class MethodBreakpoint extends BreakpointWithHighlighter {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.breakpoints.MethodBreakpoint");
+  public boolean WATCH_ENTRY = true;
+  public boolean WATCH_EXIT  = true;
+
+  @Nullable private String myMethodName;
+  @Nullable private JVMName mySignature;
+  private boolean myIsStatic;
+
+  public static final @NonNls Key<MethodBreakpoint> CATEGORY = BreakpointCategory.lookup("method_breakpoints");
+
+  protected MethodBreakpoint(@NotNull Project project) {
+    super(project);
+  }
+
+  private MethodBreakpoint(@NotNull Project project, @NotNull RangeHighlighter highlighter) {
+    super(project, highlighter);
+  }
+
+  public boolean isStatic() {
+    return myIsStatic;
+  }
+
+  @NotNull
+  public Key<MethodBreakpoint> getCategory() {
+    return CATEGORY;
+  }
+
+  @Nullable
+  public PsiMethod getPsiMethod() {
+    Document document = getDocument();
+    if(document == null) return null;
+    PsiFile psiFile = PsiDocumentManager.getInstance(myProject).getPsiFile(document);
+    if(psiFile instanceof PsiJavaFile) {
+      int line = getLineIndex();
+      final int offset = CharArrayUtil.shiftForward(document.getCharsSequence(), document.getLineStartOffset(line), " \t");
+      return DebuggerUtilsEx.findPsiMethod(psiFile, offset);
+    }
+    return null;
+  }
+
+  public boolean isValid() {
+    return super.isValid() && myMethodName != null;
+  }
+
+  protected void reload(@NotNull PsiFile psiFile) {
+    myMethodName = null;
+    mySignature = null;
+
+    MethodDescriptor descriptor = getMethodDescriptor(myProject, psiFile, getSourcePosition());
+    if (descriptor != null) {
+      myMethodName = descriptor.methodName;
+      mySignature = descriptor.methodSignature;
+      myIsStatic = descriptor.isStatic;
+    }
+    if (myIsStatic) {
+      INSTANCE_FILTERS_ENABLED = false;
+    }
+  }
+
+  protected void createRequestForPreparedClass(@NotNull DebugProcessImpl debugProcess, @NotNull ReferenceType classType) {
+    try {
+      boolean hasMethod = false;
+      for (Iterator iterator = classType.allMethods().iterator(); iterator.hasNext();) {
+        Method method = (Method)iterator.next();
+        String signature = method.signature();
+        String name = method.name();
+
+        if (myMethodName.equals(name) && mySignature.getName(debugProcess).equals(signature)) {
+          hasMethod = true;
+          break;
+        }
+      }
+
+      if(!hasMethod) {
+        debugProcess.getRequestsManager().setInvalid(
+          this, DebuggerBundle.message("error.invalid.breakpoint.method.not.found", classType.name())
+        );
+        return;
+      }
+
+      RequestManagerImpl requestManager = debugProcess.getRequestsManager();
+      if (WATCH_ENTRY) {
+        MethodEntryRequest entryRequest = (MethodEntryRequest)findRequest(debugProcess, MethodEntryRequest.class);
+        if (entryRequest == null) {
+          entryRequest = requestManager.createMethodEntryRequest(this);
+        }
+        else {
+          entryRequest.disable();
+        }
+        //entryRequest.addClassFilter(myClassQualifiedName);
+        // use addClassFilter(ReferenceType) in order to stop on subclasses also!
+        entryRequest.addClassFilter(classType);
+        debugProcess.getRequestsManager().enableRequest(entryRequest);
+      }
+      if (WATCH_EXIT) {
+        MethodExitRequest exitRequest = (MethodExitRequest)findRequest(debugProcess, MethodExitRequest.class);
+        if (exitRequest == null) {
+          exitRequest = requestManager.createMethodExitRequest(this);
+        }
+        else {
+          exitRequest.disable();
+        }
+        //exitRequest.addClassFilter(myClassQualifiedName);
+        exitRequest.addClassFilter(classType);
+        debugProcess.getRequestsManager().enableRequest(exitRequest);
+      }
+    }
+    catch (Exception e) {
+      LOG.debug(e);
+    }
+  }
+
+
+  public String getEventMessage(@NotNull LocatableEvent event) {
+    final Location location = event.location();
+    final String locationQName = location.declaringType().name() + "." + location.method().name();
+    String locationFileName = "";
+    try {
+      locationFileName = location.sourceName();
+    }
+    catch (AbsentInformationException e) {
+      locationFileName = getSourcePosition().getFile().getName();
+    }
+    final int locationLine = location.lineNumber();
+    if (event instanceof MethodEntryEvent) {
+      MethodEntryEvent entryEvent = (MethodEntryEvent)event;
+      final Method method = entryEvent.method();
+      return DebuggerBundle.message(
+        "status.method.entry.breakpoint.reached", 
+        method.declaringType().name() + "." + method.name() + "()",
+        locationQName,
+        locationFileName,
+        locationLine
+      );
+    }
+    if (event instanceof MethodExitEvent) {
+      MethodExitEvent exitEvent = (MethodExitEvent)event;
+      final Method method = exitEvent.method();
+      return DebuggerBundle.message(
+        "status.method.exit.breakpoint.reached", 
+        method.declaringType().name() + "." + method.name() + "()",
+        locationQName,
+        locationFileName,
+        locationLine
+      );
+    }
+    return "";
+  }
+
+  public PsiElement getEvaluationElement() {
+    return getPsiClass();
+  }
+
+  @NotNull
+  protected Icon getDisabledIcon(boolean isMuted) {
+    final Breakpoint master = DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager().findMasterBreakpoint(this);
+    if (isMuted) {
+      return master == null? AllIcons.Debugger.Db_muted_disabled_method_breakpoint : AllIcons.Debugger.Db_muted_dep_method_breakpoint;
+    }
+    else {
+      return master == null? AllIcons.Debugger.Db_disabled_method_breakpoint : AllIcons.Debugger.Db_dep_method_breakpoint;
+    }
+  }
+
+  @NotNull
+  protected Icon getSetIcon(boolean isMuted) {
+    return isMuted? AllIcons.Debugger.Db_muted_method_breakpoint : AllIcons.Debugger.Db_method_breakpoint;
+  }
+
+  @NotNull
+  protected Icon getInvalidIcon(boolean isMuted) {
+    return isMuted? AllIcons.Debugger.Db_muted_invalid_method_breakpoint : AllIcons.Debugger.Db_invalid_method_breakpoint;
+  }
+
+  @NotNull
+  protected Icon getVerifiedIcon(boolean isMuted) {
+    return isMuted? AllIcons.Debugger.Db_muted_verified_method_breakpoint : AllIcons.Debugger.Db_verified_method_breakpoint;
+  }
+
+  @NotNull
+  protected Icon getVerifiedWarningsIcon(boolean isMuted) {
+    return isMuted? AllIcons.Debugger.Db_muted_method_warning_breakpoint : AllIcons.Debugger.Db_method_warning_breakpoint;
+  }
+
+  public String getDisplayName() {
+    final StringBuilder buffer = StringBuilderSpinAllocator.alloc();
+    try {
+      if(isValid()) {
+        final String className = getClassName();
+        final boolean classNameExists = className != null && className.length() > 0;
+        if (classNameExists) {
+          buffer.append(className);
+        }
+        if(myMethodName != null) {
+          if (classNameExists) {
+            buffer.append(".");
+          }
+          buffer.append(myMethodName);
+        }
+      }
+      else {
+        buffer.append(DebuggerBundle.message("status.breakpoint.invalid"));
+      }
+      return buffer.toString();
+    }
+    finally {
+      StringBuilderSpinAllocator.dispose(buffer);
+    }
+  }
+
+  public boolean evaluateCondition(@NotNull EvaluationContextImpl context, @NotNull LocatableEvent event) throws EvaluateException {
+    if (!matchesEvent(event, context.getDebugProcess())) {
+      return false;
+    }
+    return super.evaluateCondition(context, event);
+  }
+
+  public boolean matchesEvent(@NotNull final LocatableEvent event, final DebugProcessImpl process) throws EvaluateException {
+    if (myMethodName == null || mySignature == null) {
+      return false;
+    }
+    final Method method = event.location().method();
+    return method != null && method.name().equals(myMethodName) && method.signature().equals(mySignature.getName(process));
+  }
+
+  @Nullable
+  public static MethodBreakpoint create(@NotNull Project project, @NotNull Document document, int lineIndex) {
+    final MethodBreakpoint breakpoint = new MethodBreakpoint(project, createHighlighter(project, document, lineIndex));
+    return (MethodBreakpoint)breakpoint.init();
+  }
+
+
+  public boolean canMoveTo(final SourcePosition position) {
+    return super.canMoveTo(position) && PositionUtil.getPsiElementAt(getProject(), PsiMethod.class, position) != null;
+  }
+
+  /**
+   * finds FQ method's class name and method's signature
+   */
+  @Nullable
+  private static MethodDescriptor getMethodDescriptor(@NotNull final Project project, @NotNull final PsiFile psiJavaFile, @NotNull final SourcePosition sourcePosition) {
+    final PsiDocumentManager docManager = PsiDocumentManager.getInstance(project);
+    final Document document = docManager.getDocument(psiJavaFile);
+    if(document == null) {
+      return null;
+    }
+    //final int endOffset = document.getLineEndOffset(sourcePosition);
+    final MethodDescriptor descriptor = docManager.commitAndRunReadAction(new Computable<MethodDescriptor>() {
+      @Nullable
+      public MethodDescriptor compute() {
+        //PsiMethod method = DebuggerUtilsEx.findPsiMethod(psiJavaFile, endOffset);
+        PsiMethod method = PositionUtil.getPsiElementAt(project, PsiMethod.class, sourcePosition);
+        if (method == null) {
+          return null;
+        }
+        final int methodOffset = method.getTextOffset();
+        if (methodOffset < 0) {
+          return null;
+        }
+        if (document.getLineNumber(methodOffset) < sourcePosition.getLine()) {
+          return null;
+        }
+
+        final PsiIdentifier identifier = method.getNameIdentifier();
+        int methodNameOffset = identifier != null? identifier.getTextOffset() : methodOffset;
+        final MethodDescriptor descriptor =
+          new MethodDescriptor();
+        //noinspection HardCodedStringLiteral
+        descriptor.methodName = method.isConstructor() ? "<init>" : method.getName();
+        try {
+          descriptor.methodSignature = JVMNameUtil.getJVMSignature(method);
+          descriptor.isStatic = method.hasModifierProperty(PsiModifier.STATIC);
+        }
+        catch (IndexNotReadyException ignored) {
+          return null;
+        }
+        descriptor.methodLine = document.getLineNumber(methodNameOffset);
+        return descriptor;
+      }
+    });
+    if (descriptor == null || descriptor.methodName == null || descriptor.methodSignature == null) {
+      return null;
+    }
+    return descriptor;
+  }
+
+  @Nullable
+  private EventRequest findRequest(@NotNull DebugProcessImpl debugProcess, Class requestClass) {
+    Set reqSet = debugProcess.getRequestsManager().findRequests(this);
+    for (Iterator iterator = reqSet.iterator(); iterator.hasNext();) {
+      EventRequest eventRequest = (EventRequest) iterator.next();
+      if(eventRequest.getClass().equals(requestClass)) {
+        return eventRequest;
+      }
+    }
+
+    return null;
+  }
+
+  public String toString() {
+    return getDescription();
+  }
+
+  public boolean isBodyAt(@NotNull Document document, int offset) {
+    PsiFile psiFile = PsiDocumentManager.getInstance(myProject).getPsiFile(document);
+    if(psiFile instanceof PsiJavaFile) {
+      PsiMethod method = DebuggerUtilsEx.findPsiMethod(psiFile, offset);
+      return method == getPsiMethod();
+    }
+
+    return false;
+  }
+
+  private static final class MethodDescriptor {
+    String methodName;
+    JVMName methodSignature;
+    boolean isStatic;
+    int methodLine;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpointFactory.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpointFactory.java
new file mode 100644
index 0000000..c2ad3dc
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpointFactory.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.breakpoints;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.HelpID;
+import com.intellij.debugger.ui.breakpoints.actions.*;
+import com.intellij.icons.AllIcons;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.openapi.util.Key;
+import org.jdom.Element;
+
+import javax.swing.*;
+import java.awt.event.ActionEvent;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: Apr 26, 2005
+ */
+public class MethodBreakpointFactory extends BreakpointFactory{
+  public Breakpoint createBreakpoint(Project project, final Element element) {
+    return element.getAttributeValue(WildcardMethodBreakpoint.JDOM_LABEL) != null? new WildcardMethodBreakpoint(project) : new MethodBreakpoint(project);
+  }
+
+  public Icon getIcon() {
+    return AllIcons.Debugger.Db_method_breakpoint;
+  }
+
+  public Icon getDisabledIcon() {
+    return AllIcons.Debugger.Db_disabled_method_breakpoint;
+  }
+
+  @Override
+  protected String getHelpID() {
+    return HelpID.METHOD_BREAKPOINTS;
+  }
+
+  @Override
+  public String getDisplayName() {
+    return DebuggerBundle.message("method.breakpoints.tab.title");
+  }
+
+  @Override
+  public BreakpointPropertiesPanel createBreakpointPropertiesPanel(Project project, boolean compact) {
+    return new MethodBreakpointPropertiesPanel(project, compact);
+  }
+
+  @Override
+  protected BreakpointPanelAction[] createBreakpointPanelActions(Project project, final DialogWrapper parentDialog) {
+    return new BreakpointPanelAction[]{
+      new SwitchViewAction(),
+      new AddAction(this, project),
+      new GotoSourceAction(project) {
+        public void actionPerformed(ActionEvent e) {
+          super.actionPerformed(e);
+          parentDialog.close(DialogWrapper.OK_EXIT_CODE);
+        }
+      },
+      new ViewSourceAction(project),
+      new RemoveAction(project),
+      new ToggleGroupByClassesAction(),
+      new ToggleFlattenPackagesAction(),
+    };
+  }
+
+  @Override
+  protected void configureBreakpointPanel(BreakpointPanel panel) {
+    super.configureBreakpointPanel(panel);
+    panel.getTree().setGroupByMethods(false);
+  }
+
+  public Key<MethodBreakpoint> getBreakpointCategory() {
+    return MethodBreakpoint.CATEGORY;
+  }
+
+  @Override
+  public boolean canAddBreakpoints() {
+    return true;
+  }
+
+  public WildcardMethodBreakpoint addBreakpoint(Project project) {
+    AddWildcardBreakpointDialog dialog = new AddWildcardBreakpointDialog(project);
+    dialog.show();
+    WildcardMethodBreakpoint methodBreakpoint;
+    methodBreakpoint = !dialog.isOK()
+                       ? null
+                       : DebuggerManagerEx.getInstanceEx(project).getBreakpointManager()
+                         .addMethodBreakpoint(dialog.getClassPattern(), dialog.getMethodName());
+    return methodBreakpoint;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpointPropertiesPanel.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpointPropertiesPanel.java
new file mode 100644
index 0000000..5298474
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpointPropertiesPanel.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/**
+ * class MethodBreakpointPropertiesPanel
+ * @author Jeka
+ */
+package com.intellij.debugger.ui.breakpoints;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.openapi.project.Project;
+import com.intellij.ui.IdeBorderFactory;
+import com.intellij.util.ui.DialogUtil;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+public class MethodBreakpointPropertiesPanel extends BreakpointPropertiesPanel {
+  private JCheckBox myWatchEntryCheckBox;
+  private JCheckBox myWatchExitCheckBox;
+
+  public MethodBreakpointPropertiesPanel(final Project project, boolean compact) {
+    super(project, MethodBreakpoint.CATEGORY, compact);
+  }
+
+  protected JComponent createSpecialBox() {
+    JPanel _panel, _panel0;
+
+    myWatchEntryCheckBox = new JCheckBox(DebuggerBundle.message("label.method.breakpoint.properties.panel.method.entry"));
+    myWatchExitCheckBox = new JCheckBox(DebuggerBundle.message("label.method.breakpoint.properties.panel.method.exit"));
+    DialogUtil.registerMnemonic(myWatchEntryCheckBox);
+    DialogUtil.registerMnemonic(myWatchExitCheckBox);
+
+
+    Box watchBox = Box.createVerticalBox();
+    _panel = new JPanel(new BorderLayout());
+    _panel.add(myWatchEntryCheckBox, BorderLayout.NORTH);
+    watchBox.add(_panel);
+    _panel = new JPanel(new BorderLayout());
+    _panel.add(myWatchExitCheckBox, BorderLayout.NORTH);
+    watchBox.add(_panel);
+
+    _panel = new JPanel(new BorderLayout());
+    _panel0 = new JPanel(new BorderLayout());
+    _panel0.add(watchBox, BorderLayout.CENTER);
+    _panel0.add(Box.createHorizontalStrut(3), BorderLayout.WEST);
+    _panel0.add(Box.createHorizontalStrut(3), BorderLayout.EAST);
+    _panel.add(_panel0, BorderLayout.NORTH);
+    _panel.setBorder(IdeBorderFactory.createTitledBorder(DebuggerBundle.message("label.group.watch.events"), true));
+
+    ActionListener listener = new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        JCheckBox toCheck = null;
+        if (!myWatchEntryCheckBox.isSelected() && !myWatchExitCheckBox.isSelected()) {
+          Object source = e.getSource();
+          if (myWatchEntryCheckBox.equals(source)) {
+            toCheck = myWatchExitCheckBox;
+          }
+          else if (myWatchExitCheckBox.equals(source)) {
+            toCheck = myWatchEntryCheckBox;
+          }
+          if (toCheck != null) {
+            toCheck.setSelected(true);
+          }
+        }
+      }
+    };
+    myWatchEntryCheckBox.addActionListener(listener);
+    myWatchExitCheckBox.addActionListener(listener);
+
+    return _panel;
+  }
+
+  public void initFrom(Breakpoint breakpoint, boolean moreOptionsVisible) {
+    super.initFrom(breakpoint, moreOptionsVisible);
+    if (breakpoint instanceof MethodBreakpoint) {
+      MethodBreakpoint methodBreakpoint = (MethodBreakpoint)breakpoint;
+      myWatchEntryCheckBox.setSelected(methodBreakpoint.WATCH_ENTRY);
+      myWatchExitCheckBox.setSelected(methodBreakpoint.WATCH_EXIT);
+    }
+    else if (breakpoint instanceof WildcardMethodBreakpoint){
+      final WildcardMethodBreakpoint methodBreakpoint = ((WildcardMethodBreakpoint)breakpoint);
+      myWatchEntryCheckBox.setSelected(methodBreakpoint.WATCH_ENTRY);
+      myWatchExitCheckBox.setSelected(methodBreakpoint.WATCH_EXIT);
+    }
+  }
+
+  public void saveTo(Breakpoint breakpoint, @NotNull Runnable afterUpdate) {
+    if (breakpoint instanceof MethodBreakpoint) {
+      MethodBreakpoint methodBreakpoint = (MethodBreakpoint)breakpoint;
+      methodBreakpoint.WATCH_ENTRY = myWatchEntryCheckBox.isSelected();
+      methodBreakpoint.WATCH_EXIT = myWatchExitCheckBox.isSelected();
+    }
+    else if (breakpoint instanceof WildcardMethodBreakpoint){
+      final WildcardMethodBreakpoint methodBreakpoint = ((WildcardMethodBreakpoint)breakpoint);
+      methodBreakpoint.WATCH_ENTRY = myWatchEntryCheckBox.isSelected();
+      methodBreakpoint.WATCH_EXIT = myWatchExitCheckBox.isSelected();
+    }
+    super.saveTo(breakpoint, afterUpdate);
+  }
+}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/RunToCursorBreakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/RunToCursorBreakpoint.java
new file mode 100644
index 0000000..7c7c5eb
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/RunToCursorBreakpoint.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.breakpoints;
+
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.markup.RangeHighlighter;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: Sep 13, 2006
+ */
+public class RunToCursorBreakpoint extends LineBreakpoint {
+  private final boolean myRestoreBreakpoints;
+
+  private RunToCursorBreakpoint(Project project, RangeHighlighter highlighter, boolean restoreBreakpoints) {
+    super(project, highlighter);
+    setVisible(false);
+    myRestoreBreakpoints = restoreBreakpoints;
+  }
+
+  public boolean isRestoreBreakpoints() {
+    return myRestoreBreakpoints;
+  }
+
+  @Override
+  public boolean isVisible() {
+    return false;
+  }
+
+  @Override
+  protected boolean isMuted(@NotNull final DebugProcessImpl debugProcess) {
+    return false;  // always enabled
+  }
+
+  @Nullable
+  protected static RunToCursorBreakpoint create(@NotNull Project project, @NotNull Document document, int lineIndex, boolean restoreBreakpoints) {
+    VirtualFile virtualFile = FileDocumentManager.getInstance().getFile(document);
+    if (virtualFile == null) {
+      return null;
+    }
+
+    final RangeHighlighter highlighter = createHighlighter(project, document, lineIndex);
+    if (highlighter == null) {
+      return null;
+    }
+
+    final RunToCursorBreakpoint breakpoint = new RunToCursorBreakpoint(project, highlighter, restoreBreakpoints);
+    breakpoint.getHighlighter().dispose();
+
+    return (RunToCursorBreakpoint)breakpoint.init();
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/WildcardMethodBreakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/WildcardMethodBreakpoint.java
new file mode 100644
index 0000000..f6c0dc3
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/WildcardMethodBreakpoint.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright 2004-2006 Alexey Efimov
+ *
+ * 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.debugger.ui.breakpoints;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.engine.DebugProcess;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.engine.requests.RequestManagerImpl;
+import com.intellij.icons.AllIcons;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.Key;
+import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiElement;
+import com.intellij.util.StringBuilderSpinAllocator;
+import com.sun.jdi.AbsentInformationException;
+import com.sun.jdi.Location;
+import com.sun.jdi.Method;
+import com.sun.jdi.ReferenceType;
+import com.sun.jdi.event.LocatableEvent;
+import com.sun.jdi.event.MethodEntryEvent;
+import com.sun.jdi.event.MethodExitEvent;
+import com.sun.jdi.request.EventRequest;
+import com.sun.jdi.request.MethodEntryRequest;
+import com.sun.jdi.request.MethodExitRequest;
+import org.jdom.Element;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.util.Iterator;
+import java.util.Set;
+
+public class WildcardMethodBreakpoint extends Breakpoint {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.breakpoints.ExceptionBreakpoint");
+
+  public boolean WATCH_ENTRY = true;
+  public boolean WATCH_EXIT  = true;
+  private String myClassPattern;
+  private String myMethodName;
+
+  public static final String JDOM_LABEL = "wildcard_breakpoint";
+
+  public WildcardMethodBreakpoint(Project project) {
+    super(project);
+  }
+
+  public Key<MethodBreakpoint> getCategory() {
+    return MethodBreakpoint.CATEGORY;
+  }
+
+  protected WildcardMethodBreakpoint(Project project, @NotNull String classPattern, @NotNull String methodName) {
+    super(project);
+    myClassPattern = classPattern;
+    myMethodName = methodName;
+  }
+
+  public String getClassName() {
+    return myClassPattern;
+  }
+
+  public @Nullable String getShortClassName() {
+    return getClassName();
+  }
+
+  public String getMethodName() {
+    return myMethodName;
+  }
+
+  public PsiClass getPsiClass() {
+    return null;
+  }
+
+  public String getDisplayName() {
+    if (!isValid()) {
+      return DebuggerBundle.message("status.breakpoint.invalid");
+    }
+    final StringBuilder buffer = StringBuilderSpinAllocator.alloc();
+    try {
+      buffer.append(myClassPattern);
+      buffer.append(".");
+      buffer.append(myMethodName);
+      buffer.append("()");
+      return buffer.toString();
+    }
+    finally {
+      StringBuilderSpinAllocator.dispose(buffer);
+    }
+  }
+
+  public Icon getIcon() {
+    if (!ENABLED) {
+      final Breakpoint master = DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager().findMasterBreakpoint(this);
+      return master == null? AllIcons.Debugger.Db_disabled_method_breakpoint : AllIcons.Debugger.Db_dep_method_breakpoint;
+    }
+    return AllIcons.Debugger.Db_method_breakpoint;
+  }
+
+  public void reload() {
+  }
+
+  public boolean evaluateCondition(EvaluationContextImpl context, LocatableEvent event) throws EvaluateException {
+    return matchesEvent(event) && super.evaluateCondition(context, event);
+  }
+
+  public void createRequest(DebugProcessImpl debugProcess) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    if (!ENABLED || !debugProcess.isAttached() || debugProcess.areBreakpointsMuted() || !debugProcess.getRequestsManager().findRequests(this).isEmpty()) {
+      return;
+    }
+    try {
+      RequestManagerImpl requestManager = debugProcess.getRequestsManager();
+      if (WATCH_ENTRY) {
+        MethodEntryRequest entryRequest = (MethodEntryRequest)findRequest(debugProcess, MethodEntryRequest.class);
+        if (entryRequest == null) {
+          entryRequest = requestManager.createMethodEntryRequest(this);
+        }
+        else {
+          entryRequest.disable();
+        }
+        entryRequest.addClassFilter(myClassPattern);
+        debugProcess.getRequestsManager().enableRequest(entryRequest);
+      }
+      if (WATCH_EXIT) {
+        MethodExitRequest exitRequest = (MethodExitRequest)findRequest(debugProcess, MethodExitRequest.class);
+        if (exitRequest == null) {
+          exitRequest = requestManager.createMethodExitRequest(this);
+        }
+        else {
+          exitRequest.disable();
+        }
+        exitRequest.addClassFilter(myClassPattern);
+        debugProcess.getRequestsManager().enableRequest(exitRequest);
+      }
+    }
+    catch (Exception e) {
+      LOG.debug(e);
+    }
+  }
+
+  private EventRequest findRequest(DebugProcessImpl debugProcess, Class requestClass) {
+    Set reqSet = debugProcess.getRequestsManager().findRequests(this);
+    for (Iterator iterator = reqSet.iterator(); iterator.hasNext();) {
+      EventRequest eventRequest = (EventRequest) iterator.next();
+      if(eventRequest.getClass().equals(requestClass)) {
+        return eventRequest;
+      }
+    }
+
+    return null;
+  }
+
+  public void processClassPrepare(DebugProcess debugProcess, ReferenceType refType) {
+    // should be emty - does not make sense for this breakpoint
+  }
+
+  public String getEventMessage(LocatableEvent event) {
+    final Location location = event.location();
+    final String locationQName = location.declaringType().name() + "." + location.method().name();
+    String locationFileName = "";
+    try {
+      locationFileName = location.sourceName();
+    }
+    catch (AbsentInformationException e) {
+      locationFileName = "";
+    }
+    final int locationLine = location.lineNumber();
+    
+    if (event instanceof MethodEntryEvent) {
+      MethodEntryEvent entryEvent = (MethodEntryEvent)event;
+      final Method method = entryEvent.method();
+      return DebuggerBundle.message(
+        "status.method.entry.breakpoint.reached", 
+        method.declaringType().name() + "." + method.name() + "()",
+        locationQName,
+        locationFileName,
+        locationLine
+      );
+    }
+    
+    if (event instanceof MethodExitEvent) {
+      MethodExitEvent exitEvent = (MethodExitEvent)event;
+      final Method method = exitEvent.method();
+      return DebuggerBundle.message(
+        "status.method.exit.breakpoint.reached", 
+        method.declaringType().name() + "." + method.name() + "()",
+        locationQName,
+        locationFileName,
+        locationLine
+      );
+    }
+    return "";
+  }
+
+  public boolean isValid() {
+    return myClassPattern != null && myMethodName != null;
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"}) public void writeExternal(Element parentNode) throws WriteExternalException {
+    super.writeExternal(parentNode);
+    parentNode.setAttribute(JDOM_LABEL, "true");
+    if (myClassPattern != null) {
+      parentNode.setAttribute("class_name", myClassPattern);
+    }
+    if (myMethodName != null) {
+      parentNode.setAttribute("method_name", myMethodName);
+    }
+  }
+
+  public PsiElement getEvaluationElement() {
+    return null;
+  }
+
+  public void readExternal(Element parentNode) throws InvalidDataException {
+    super.readExternal(parentNode);
+
+    //noinspection HardCodedStringLiteral
+    String className = parentNode.getAttributeValue("class_name");
+    myClassPattern = className;
+
+    //noinspection HardCodedStringLiteral
+    String methodName = parentNode.getAttributeValue("method_name");
+    myMethodName = methodName;
+
+    if(className == null || methodName == null) {
+      throw new InvalidDataException();
+    }
+  }
+
+  public boolean matchesEvent(final LocatableEvent event){
+    final Method method = event.location().method();
+    return method != null && myMethodName.equals(method.name());
+  }
+
+  public static WildcardMethodBreakpoint create(Project project, final String classPattern, final String methodName) {
+    return new WildcardMethodBreakpoint(project, classPattern, methodName);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/AddAction.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/AddAction.java
new file mode 100644
index 0000000..8e3b37e
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/AddAction.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.breakpoints.actions;
+
+import com.intellij.debugger.ui.breakpoints.Breakpoint;
+import com.intellij.debugger.ui.breakpoints.BreakpointFactory;
+import com.intellij.debugger.ui.breakpoints.BreakpointPanel;
+import com.intellij.ide.IdeBundle;
+import com.intellij.openapi.project.Project;
+
+import javax.swing.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: May 25, 2005
+ */
+public class AddAction extends BreakpointPanelAction {
+  protected final Project myProject;
+  protected BreakpointFactory myBreakpointFactory;
+
+  public AddAction(BreakpointFactory breakpointFactory, Project project) {
+    super(IdeBundle.message("button.add"));
+    myProject = project;
+    this.myBreakpointFactory = breakpointFactory;
+  }
+
+  public void setPanel(BreakpointPanel panel) {
+    super.setPanel(panel);
+    getPanel().getTable().registerKeyboardAction(this, KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
+  }
+
+  public void update() {
+  }
+
+  public void actionPerformed(ActionEvent e) {
+    Breakpoint breakpoint = myBreakpointFactory.addBreakpoint(myProject);
+    if (breakpoint != null) {
+      getPanel().addBreakpoint(breakpoint);
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/BreakpointPanelAction.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/BreakpointPanelAction.java
new file mode 100644
index 0000000..32e7f5c
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/BreakpointPanelAction.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.breakpoints.actions;
+
+import com.intellij.debugger.ui.breakpoints.BreakpointPanel;
+
+import javax.swing.*;
+import java.awt.event.ActionListener;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: May 25, 2005
+ */
+public abstract class BreakpointPanelAction implements ActionListener {
+  private final String myName;
+  private AbstractButton myButton;
+  private BreakpointPanel myPanel;
+
+  protected BreakpointPanelAction(String name) {
+    myName = name;
+  }
+
+  public final String getName() {
+    return myName;
+  }
+
+  public boolean isStateAction() {
+    return false;
+  }
+
+  public void setPanel(BreakpointPanel panel) {
+    myPanel = panel;
+  }
+
+  public final BreakpointPanel getPanel() {
+    return myPanel;
+  }
+
+  public void setButton(AbstractButton button) {
+    myButton = button;
+  }
+
+  public final AbstractButton getButton() {
+    return myButton;
+  }
+
+  public abstract void update();
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/FocusOnBreakpointAction.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/FocusOnBreakpointAction.java
new file mode 100644
index 0000000..91b223c
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/FocusOnBreakpointAction.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.breakpoints.actions;
+
+import com.intellij.execution.ui.actions.AbstractFocusOnAction;
+import com.intellij.xdebugger.impl.ui.XDebuggerUIConstants;
+
+public class FocusOnBreakpointAction extends AbstractFocusOnAction {
+  public FocusOnBreakpointAction() {
+    super(XDebuggerUIConstants.LAYOUT_VIEW_BREAKPOINT_CONDITION);
+  }
+}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/GotoSourceAction.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/GotoSourceAction.java
new file mode 100644
index 0000000..aedbfb4
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/GotoSourceAction.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.breakpoints.actions;
+
+import com.intellij.debugger.ui.breakpoints.BreakpointPanel;
+import com.intellij.ide.IdeBundle;
+import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.fileEditor.FileEditorManager;
+import com.intellij.openapi.fileEditor.OpenFileDescriptor;
+import com.intellij.openapi.project.Project;
+
+import java.awt.event.ActionEvent;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: May 25, 2005
+ */
+public class GotoSourceAction extends BreakpointPanelAction {
+  private final Project myProject;
+
+  protected GotoSourceAction(final Project project) {
+    super(IdeBundle.message("button.go.to"));
+    myProject = project;
+  }
+
+  public void actionPerformed(ActionEvent e) {
+    gotoSource();
+  }
+
+  private void gotoSource() {
+    OpenFileDescriptor editSourceDescriptor = getPanel().createEditSourceDescriptor(myProject);
+    if (editSourceDescriptor != null) {
+      FileEditorManager.getInstance(myProject).openTextEditor(editSourceDescriptor, true);
+    }
+  }
+
+  public void setPanel(BreakpointPanel panel) {
+    super.setPanel(panel);
+    ShortcutSet shortcutSet = ActionManager.getInstance().getAction(IdeActions.ACTION_EDIT_SOURCE).getShortcutSet();
+    new AnAction() {
+      public void actionPerformed(AnActionEvent e){
+        gotoSource();
+      }
+    }.registerCustomShortcutSet(shortcutSet, getPanel().getPanel());
+  }
+
+  public void update() {
+    getButton().setEnabled(getPanel().getCurrentViewableBreakpoint() != null);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/RemoveAction.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/RemoveAction.java
new file mode 100644
index 0000000..72a86b7
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/RemoveAction.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.breakpoints.actions;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.ui.breakpoints.AnyExceptionBreakpoint;
+import com.intellij.debugger.ui.breakpoints.Breakpoint;
+import com.intellij.debugger.ui.breakpoints.BreakpointManager;
+import com.intellij.debugger.ui.breakpoints.BreakpointPanel;
+import com.intellij.openapi.project.Project;
+
+import javax.swing.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: May 25, 2005
+ */
+public class RemoveAction extends BreakpointPanelAction {
+  private final Project myProject;
+
+  public RemoveAction(final Project project) {
+    super(DebuggerBundle.message("button.remove"));
+    myProject = project;
+  }
+
+
+  public void setPanel(BreakpointPanel panel) {
+    super.setPanel(panel);
+    getPanel().getTable().registerKeyboardAction(
+      this, KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
+    );
+    getPanel().getTree().registerKeyboardAction(
+      this, KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
+    );
+  }
+
+  public void actionPerformed(ActionEvent e) {
+    Breakpoint[] breakpoints = getPanel().getSelectedBreakpoints();
+    if (breakpoints != null) {
+      for (Breakpoint breakpoint1 : breakpoints) {
+        if (breakpoint1 instanceof AnyExceptionBreakpoint) {
+          return;
+        }
+      }
+      getPanel().removeSelectedBreakpoints();
+      BreakpointManager manager = DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager();
+      for (final Breakpoint breakpoint : breakpoints) {
+        getPanel().getTree().removeBreakpoint(breakpoint);
+        manager.removeBreakpoint(breakpoint);
+      }
+    }
+  }
+
+  public void update() {
+    getButton().setEnabled(getPanel().getSelectedBreakpoints().length > 0);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/SwitchViewAction.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/SwitchViewAction.java
new file mode 100644
index 0000000..8a44fbb
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/SwitchViewAction.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.breakpoints.actions;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.ui.breakpoints.BreakpointPanel;
+
+import javax.swing.*;
+import java.awt.event.ActionEvent;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: May 25, 2005
+ */
+public class SwitchViewAction extends BreakpointPanelAction {
+  public SwitchViewAction() {
+    super(DebuggerBundle.message("button.switch.view"));
+  }
+
+
+  public void actionPerformed(ActionEvent e) {
+    getPanel().switchViews();
+  }
+
+
+  public void update() {
+    final AbstractButton button = getButton();
+    final BreakpointPanel panel = getPanel();
+    button.setText(panel.isTreeShowing()? DebuggerBundle.message("button.list.view") : DebuggerBundle.message("button.tree.view"));
+    button.setEnabled(panel.getBreakpointCount() > 0);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/ToggleFlattenPackagesAction.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/ToggleFlattenPackagesAction.java
new file mode 100644
index 0000000..d6681f4
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/ToggleFlattenPackagesAction.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.breakpoints.actions;
+
+import com.intellij.debugger.ui.breakpoints.BreakpointPanel;
+import com.intellij.debugger.DebuggerBundle;
+
+import javax.swing.*;
+import java.awt.event.ActionEvent;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: May 25, 2005
+ */
+public class ToggleFlattenPackagesAction extends BreakpointPanelAction {
+  public ToggleFlattenPackagesAction() {
+    super(DebuggerBundle.message("button.flatten.packages"));
+  }
+
+  public boolean isStateAction() {
+    return true;
+  }
+
+  public void setButton(AbstractButton button) {
+    super.setButton(button);
+    getButton().setSelected(getPanel().getTree().isFlattenPackages());
+  }
+
+  public void actionPerformed(ActionEvent e) {
+    getPanel().getTree().setFlattenPackages(getButton().isSelected());
+  }
+
+  public void update() {
+    final AbstractButton button = getButton();
+    final BreakpointPanel panel = getPanel();
+    button.setEnabled(panel.getBreakpointCount() > 0 && panel.isTreeShowing());
+    button.setSelected(panel.getTree().isFlattenPackages());
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/ToggleGroupByClassesAction.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/ToggleGroupByClassesAction.java
new file mode 100644
index 0000000..7dec6f3
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/ToggleGroupByClassesAction.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.breakpoints.actions;
+
+import com.intellij.debugger.ui.breakpoints.BreakpointPanel;
+import com.intellij.debugger.DebuggerBundle;
+
+import javax.swing.*;
+import java.awt.event.ActionEvent;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: May 25, 2005
+ */
+public class ToggleGroupByClassesAction extends BreakpointPanelAction {
+  public ToggleGroupByClassesAction() {
+    super(DebuggerBundle.message("button.group.by.classes"));
+  }
+
+  public boolean isStateAction() {
+    return true;
+  }
+
+  public void setButton(AbstractButton button) {
+    super.setButton(button);
+    getButton().setSelected(getPanel().getTree().isGroupByClasses());
+  }
+
+  public void actionPerformed(ActionEvent e) {
+    getPanel().getTree().setGroupByClasses(getButton().isSelected());
+  }
+
+  public void update() {
+    final AbstractButton button = getButton();
+    final BreakpointPanel panel = getPanel();
+    button.setEnabled(panel.getBreakpointCount() > 0 && panel.isTreeShowing());
+    button.setSelected(panel.getTree().isGroupByClasses());
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/ToggleGroupByMethodsAction.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/ToggleGroupByMethodsAction.java
new file mode 100644
index 0000000..57fcabe
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/ToggleGroupByMethodsAction.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.breakpoints.actions;
+
+import com.intellij.debugger.ui.breakpoints.BreakpointPanel;
+import com.intellij.debugger.DebuggerBundle;
+
+import javax.swing.*;
+import java.awt.event.ActionEvent;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: May 25, 2005
+ */
+public class ToggleGroupByMethodsAction extends BreakpointPanelAction {
+  public ToggleGroupByMethodsAction() {
+    super(DebuggerBundle.message("button.group.by.methods"));
+  }
+
+  public boolean isStateAction() {
+    return true;
+  }
+
+  public void setButton(AbstractButton button) {
+    super.setButton(button);
+    getButton().setSelected(getPanel().getTree().isGroupByMethods());
+  }
+
+  public void actionPerformed(ActionEvent e) {
+    getPanel().getTree().setGroupByMethods(getButton().isSelected());
+  }
+
+  public void update() {
+    final AbstractButton button = getButton();
+    final BreakpointPanel panel = getPanel();
+    button.setEnabled(panel.getBreakpointCount() > 0 && panel.isTreeShowing());
+    button.setSelected(panel.getTree().isGroupByMethods());
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/ViewSourceAction.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/ViewSourceAction.java
new file mode 100644
index 0000000..0744ef9
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/ViewSourceAction.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.breakpoints.actions;
+
+import com.intellij.ide.IdeBundle;
+import com.intellij.openapi.fileEditor.FileEditorManager;
+import com.intellij.openapi.fileEditor.OpenFileDescriptor;
+import com.intellij.openapi.project.Project;
+
+import java.awt.event.ActionEvent;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: May 25, 2005
+ */
+public class ViewSourceAction extends BreakpointPanelAction {
+  private final Project myProject;
+
+  public ViewSourceAction(final Project project) {
+    super(IdeBundle.message("button.view.source"));
+    myProject = project;
+  }
+
+
+  public void actionPerformed(ActionEvent e) {
+    OpenFileDescriptor editSourceDescriptor = getPanel().createEditSourceDescriptor(myProject);
+    if (editSourceDescriptor != null) {
+      FileEditorManager.getInstance(myProject).openTextEditor(editSourceDescriptor, false);
+    }
+  }
+
+  public void update() {
+    getButton().setEnabled(getPanel().getCurrentViewableBreakpoint() != null);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/content/DebuggerContentUIFacade.java b/java/debugger/impl/src/com/intellij/debugger/ui/content/DebuggerContentUIFacade.java
new file mode 100644
index 0000000..9d0bcbc
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/content/DebuggerContentUIFacade.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.content;
+
+import com.intellij.ui.content.ContentUI;
+
+public interface DebuggerContentUIFacade {
+
+  ContentUI getContentUI();
+
+  void restoreLayout();
+
+  boolean isHorizontalToolbar();
+
+  void setHorizontalToolbar(final boolean state);
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/DebuggerComboBoxRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/DebuggerComboBoxRenderer.java
new file mode 100644
index 0000000..015884f
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/DebuggerComboBoxRenderer.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2000-2012 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.debugger.ui.impl;
+
+import com.intellij.debugger.ui.impl.watch.StackFrameDescriptorImpl;
+import com.intellij.debugger.ui.impl.watch.ThreadDescriptorImpl;
+import com.intellij.ui.ListCellRendererWrapper;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+
+public class DebuggerComboBoxRenderer extends ListCellRendererWrapper {
+  public DebuggerComboBoxRenderer(final ListCellRenderer listCellRenderer) {
+    super();
+  }
+
+  @Override
+  public void customize(JList list, Object value, int index, boolean selected, boolean hasFocus) {
+    if (list.getComponentCount() > 0) {
+      Icon icon = getIcon(value);
+      if (icon != null) {
+        setIcon(icon);
+      }
+    }
+    else {
+      setIcon(null);
+    }
+  }
+
+  @Nullable
+  private static Icon getIcon(Object item) {
+    if (item instanceof ThreadDescriptorImpl) {
+      return ((ThreadDescriptorImpl)item).getIcon();
+    }
+    if (item instanceof StackFrameDescriptorImpl) {
+      return ((StackFrameDescriptorImpl)item).getIcon();
+    }
+    return null;
+  }
+}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/DebuggerTreeBase.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/DebuggerTreeBase.java
new file mode 100644
index 0000000..f515f94
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/DebuggerTreeBase.java
@@ -0,0 +1,347 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class DebuggerTreeBase
+ * @author Jeka
+ */
+package com.intellij.debugger.ui.impl;
+
+import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
+import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl;
+import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl;
+import com.intellij.ide.dnd.aware.DnDAwareTree;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.fileTypes.StdFileTypes;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.util.JDOMUtil;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
+import com.intellij.ui.ScreenUtil;
+import com.intellij.ui.ScrollPaneFactory;
+import com.intellij.util.text.StringTokenizer;
+import com.intellij.util.ui.GeometryUtil;
+import com.intellij.util.ui.UIUtil;
+import com.intellij.util.ui.tree.TreeUtil;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import javax.swing.border.Border;
+import javax.swing.tree.TreeModel;
+import javax.swing.tree.TreePath;
+import java.awt.*;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+
+
+public class DebuggerTreeBase extends DnDAwareTree implements Disposable {
+  private final Project myProject;
+  private DebuggerTreeNodeImpl myCurrentTooltipNode;
+
+  private JComponent myCurrentTooltip;
+
+  protected final TipManager myTipManager;
+
+  public DebuggerTreeBase(TreeModel model, Project project) {
+    super(model);
+    myProject = project;
+
+    myTipManager = new TipManager(this, new TipManager.TipFactory() {
+      @Override
+      public JComponent createToolTip(MouseEvent e) {
+        return DebuggerTreeBase.this.createToolTip(e);
+      }
+
+      @Override
+      public MouseEvent createTooltipEvent(MouseEvent candidateEvent) {
+        return DebuggerTreeBase.this.createTooltipEvent(candidateEvent);
+      }
+
+      @Override
+      public boolean isFocusOwner() {
+        return DebuggerTreeBase.this.isFocusOwner();
+      }
+    });
+
+    Disposer.register(this, myTipManager);
+
+    UIUtil.setLineStyleAngled(this);
+    setRootVisible(false);
+    setShowsRootHandles(true);
+    setCellRenderer(new DebuggerTreeRenderer());
+    updateUI();
+    TreeUtil.installActions(this);
+  }
+
+  private JComponent createTipContent(String tipText, DebuggerTreeNodeImpl node) {
+    final JToolTip tooltip = new JToolTip();
+
+    if (tipText == null) {
+      tooltip.setTipText(tipText);
+    }
+    else {
+      Dimension rootSize = getVisibleRect().getSize();
+      Insets borderInsets = tooltip.getBorder().getBorderInsets(tooltip);
+      rootSize.width -= (borderInsets.left + borderInsets.right) * 2;
+      rootSize.height -= (borderInsets.top + borderInsets.bottom) * 2;
+
+      @NonNls StringBuilder tipBuilder = new StringBuilder();
+      final String markupText = node.getMarkupTooltipText();
+      if (markupText != null) {
+        tipBuilder.append(markupText);
+      }
+
+      if (!tipText.isEmpty()) {
+        final StringTokenizer tokenizer = new StringTokenizer(tipText, "\n ", true);
+
+        while (tokenizer.hasMoreElements()) {
+          final String each = tokenizer.nextElement();
+          if ("\n".equals(each)) {
+            tipBuilder.append("<br>");
+          }
+          else if (" ".equals(each)) {
+            tipBuilder.append("&nbsp ");
+          }
+          else {
+            tipBuilder.append(JDOMUtil.legalizeText(each));
+          }
+        }
+      }
+
+      tooltip.setTipText(UIUtil.toHtml(tipBuilder.toString(), 0));
+    }
+
+    tooltip.setBorder(null);
+
+    return tooltip;
+  }
+
+  public MouseEvent createTooltipEvent(MouseEvent candidate) {
+    TreePath path = null;
+
+    if (candidate != null) {
+      final Point treePoint = SwingUtilities.convertPoint(candidate.getComponent(), candidate.getPoint(), this);
+      if (GeometryUtil.isWithin(new Rectangle(0, 0, getWidth(), getHeight()), treePoint)) {
+        path = getPathForLocation(treePoint.x, treePoint.y);
+      }
+    }
+
+    if (path == null) {
+      if (isFocusOwner()) {
+        path = getSelectionPath();
+      }
+    }
+
+    if (path == null) return null;
+
+    final int row = getRowForPath(path);
+    if (row == -1) return null;
+
+    final Rectangle bounds = getRowBounds(row);
+
+    return new MouseEvent(this, MouseEvent.MOUSE_MOVED, System.currentTimeMillis(), 0, bounds.x,
+                          bounds.y + bounds.height - bounds.height / 4, 0, false);
+  }
+
+  @Nullable
+  public JComponent createToolTip(MouseEvent e) {
+    final DebuggerTreeNodeImpl node = getNodeToShowTip(e);
+    if (node == null) {
+      return null;
+    }
+
+    if (myCurrentTooltip != null && myCurrentTooltip.isShowing() && myCurrentTooltipNode == node) {
+      return myCurrentTooltip;
+    }
+
+    myCurrentTooltipNode = node;
+
+    final String toolTipText = getTipText(node);
+    if (toolTipText == null) {
+      return null;
+    }
+
+    final JComponent tipContent = createTipContent(toolTipText, node);
+    final JScrollPane scrollPane = ScrollPaneFactory.createScrollPane(tipContent);
+    scrollPane.setBorder(null);
+    scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+    scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
+
+    final Point point = e.getPoint();
+    SwingUtilities.convertPointToScreen(point, e.getComponent());
+    Rectangle tipRectangle = new Rectangle(point, tipContent.getPreferredSize());
+
+    final Rectangle screen = ScreenUtil.getScreenRectangle(point.x, point.y);
+
+    final JToolTip toolTip = new JToolTip();
+
+    tipContent.addMouseListener(new HideTooltip(toolTip));
+
+    final Border tooltipBorder = toolTip.getBorder();
+    if (tooltipBorder != null) {
+      final Insets borderInsets = tooltipBorder.getBorderInsets(this);
+      tipRectangle
+        .setSize(tipRectangle.width + borderInsets.left + borderInsets.right, tipRectangle.height + borderInsets.top + borderInsets.bottom);
+    }
+
+    toolTip.setLayout(new BorderLayout());
+    toolTip.add(scrollPane, BorderLayout.CENTER);
+
+
+    tipRectangle.height += scrollPane.getHorizontalScrollBar().getPreferredSize().height;
+    tipRectangle.width += scrollPane.getVerticalScrollBar().getPreferredSize().width;
+
+
+    final int maxWidth = (int)(screen.width - screen.width * .25);
+    if (tipRectangle.width > maxWidth) {
+      tipRectangle.width = maxWidth;
+    }
+
+    final Dimension prefSize = tipRectangle.getSize();
+
+    ScreenUtil.cropRectangleToFitTheScreen(tipRectangle);
+
+    if (prefSize.width > tipRectangle.width) {
+      final int delta = prefSize.width - tipRectangle.width;
+      tipRectangle.x -= delta;
+      if (tipRectangle.x < screen.x) {
+        tipRectangle.x = screen.x + maxWidth / 2;
+        tipRectangle.width = screen.width - maxWidth / 2;
+      }
+      else {
+        tipRectangle.width += delta;
+      }
+    }
+
+    toolTip.setPreferredSize(tipRectangle.getSize());
+
+    myCurrentTooltip = toolTip;
+
+    return myCurrentTooltip;
+  }
+
+  @Nullable
+  private String getTipText(DebuggerTreeNodeImpl node) {
+    NodeDescriptorImpl descriptor = node.getDescriptor();
+    if (descriptor instanceof ValueDescriptorImpl) {
+      String text = ((ValueDescriptorImpl)descriptor).getValueLabel();
+      if (text != null) {
+        if (StringUtil.startsWithChar(text, '{') && text.indexOf('}') > 0) {
+          int idx = text.indexOf('}');
+          if (idx != text.length() - 1) {
+            text = text.substring(idx + 1);
+          }
+        }
+
+        if (StringUtil.startsWithChar(text, '\"') && StringUtil.endsWithChar(text, '\"')) {
+          text = text.substring(1, text.length() - 1);
+        }
+
+        final String tipText = prepareToolTipText(text);
+        if (!tipText.isEmpty() &&
+            (tipText.indexOf('\n') >= 0 || !getVisibleRect().contains(getRowBounds(getRowForPath(new TreePath(node.getPath())))))) {
+          return tipText;
+        }
+      }
+    }
+    return node.getMarkupTooltipText() != null? "" : null;
+  }
+
+  @Nullable
+  private DebuggerTreeNodeImpl getNodeToShowTip(MouseEvent event) {
+    TreePath path = getPathForLocation(event.getX(), event.getY());
+    if (path != null) {
+      Object last = path.getLastPathComponent();
+      if (last instanceof DebuggerTreeNodeImpl) {
+        return (DebuggerTreeNodeImpl)last;
+      }
+    }
+
+    return null;
+  }
+
+  private String prepareToolTipText(String text) {
+    int tabSize = CodeStyleSettingsManager.getSettings(myProject).getTabSize(StdFileTypes.JAVA);
+    if (tabSize < 0) {
+      tabSize = 0;
+    }
+    final StringBuilder buf = new StringBuilder();
+    boolean special = false;
+    for (int idx = 0; idx < text.length(); idx++) {
+      char c = text.charAt(idx);
+      if (special) {
+        if (c == 't') { // convert tabs to spaces
+          for (int i = 0; i < tabSize; i++) {
+            buf.append(' ');
+          }
+        }
+        else if (c == 'r') { // remove occurrences of '\r'
+        }
+        else if (c == 'n') {
+          buf.append('\n');
+        }
+        else {
+          buf.append('\\');
+          buf.append(c);
+        }
+        special = false;
+      }
+      else {
+        if (c == '\\') {
+          special = true;
+        }
+        else {
+          buf.append(c);
+        }
+      }
+    }
+    return buf.toString();
+  }
+
+  @Override
+  public void dispose() {
+    final JComponent tooltip = myCurrentTooltip;
+    if (tooltip != null) {
+      tooltip.setVisible(false);
+    }
+    myCurrentTooltip = null;
+    myCurrentTooltipNode = null;
+  }
+
+  public Project getProject() {
+    return myProject;
+  }
+
+  private static class HideTooltip extends MouseAdapter {
+    private final JToolTip myToolTip;
+
+    public HideTooltip(JToolTip toolTip) {
+      myToolTip = toolTip;
+    }
+
+    @Override
+    public void mouseReleased(MouseEvent e) {
+      if (UIUtil.isActionClick(e)) {
+        final Window wnd = SwingUtilities.getWindowAncestor(myToolTip);
+        if (wnd instanceof JWindow) {
+          wnd.setVisible(false);
+        }
+      }
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/DebuggerTreePanel.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/DebuggerTreePanel.java
new file mode 100644
index 0000000..9caf776
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/DebuggerTreePanel.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * @author Eugene Zhuravlev
+ */
+package com.intellij.debugger.ui.impl;
+
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerStateManager;
+import com.intellij.debugger.ui.impl.watch.DebuggerTree;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.application.ModalityState;
+import com.intellij.openapi.keymap.KeymapManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.wm.ex.IdeFocusTraversalPolicy;
+import com.intellij.ui.PopupHandler;
+import com.intellij.util.Alarm;
+import com.intellij.xdebugger.impl.actions.XDebuggerActions;
+import com.sun.jdi.VMDisconnectedException;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.KeyEvent;
+
+public abstract class DebuggerTreePanel extends UpdatableDebuggerView implements DataProvider {
+  public static final DataKey<DebuggerTreePanel> DATA_KEY = DataKey.create("DebuggerPanel");
+  
+  private final Alarm myRebuildAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD);
+  protected DebuggerTree myTree;
+
+  public DebuggerTreePanel(Project project, DebuggerStateManager stateManager) {
+    super(project, stateManager);
+    myTree = createTreeView();
+
+    final PopupHandler popupHandler = new PopupHandler() {
+      public void invokePopup(Component comp, int x, int y) {
+        ActionPopupMenu popupMenu = createPopupMenu();
+        if (popupMenu != null) {
+          myTree.myTipManager.registerPopup(popupMenu.getComponent()).show(comp, x, y);
+        }
+      }
+    };
+    myTree.addMouseListener(popupHandler);
+
+    setFocusTraversalPolicy(new IdeFocusTraversalPolicy() {
+      public Component getDefaultComponentImpl(Container focusCycleRoot) {
+        return myTree;
+      }
+    });
+
+    registerDisposable(new Disposable() {
+      public void dispose() {
+        myTree.removeMouseListener(popupHandler);
+      }
+    });
+
+    final Shortcut[] shortcuts = KeymapManager.getInstance().getActiveKeymap().getShortcuts("ToggleBookmark");
+    final CustomShortcutSet shortcutSet = shortcuts.length > 0? new CustomShortcutSet(shortcuts) : new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_F11, 0));
+    overrideShortcut(myTree, XDebuggerActions.MARK_OBJECT, shortcutSet);
+  }
+
+  protected abstract DebuggerTree createTreeView();
+
+
+  protected void rebuild(int event) {
+    myRebuildAlarm.cancelAllRequests();
+    myRebuildAlarm.addRequest(new Runnable() {
+      public void run() {
+        try {
+          final DebuggerContextImpl context = getContext();
+          if(context.getDebuggerSession() != null) {
+            getTree().rebuild(context);
+          }
+        }
+        catch (VMDisconnectedException e) {
+          // ignored
+        }
+      }
+    }, 100, ModalityState.NON_MODAL);
+  }
+
+  public void dispose() {
+    Disposer.dispose(myRebuildAlarm);
+    try {
+      super.dispose();
+    }
+    finally {
+      final DebuggerTree tree = myTree;
+      if (tree != null) {
+        Disposer.dispose(tree);
+      }
+      // prevent mem leak from inside Swing
+      myTree = null;
+    }
+  }
+
+
+  protected abstract ActionPopupMenu createPopupMenu();
+
+  public final DebuggerTree getTree() {
+    return myTree;
+  }
+
+  public void clear() {
+    myTree.removeAllChildren();
+  }
+
+  public Object getData(String dataId) {
+    if (DebuggerTreePanel.DATA_KEY.is(dataId)) {
+      return this;
+    }
+    return null;
+  }
+
+  public void requestFocus() {
+    getTree().requestFocus();
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/DebuggerTreeRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/DebuggerTreeRenderer.java
new file mode 100644
index 0000000..e515575
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/DebuggerTreeRenderer.java
@@ -0,0 +1,293 @@
+/*
+ * Copyright 2000-2012 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.debugger.ui.impl;
+
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.ui.impl.watch.*;
+import com.intellij.debugger.ui.tree.ValueDescriptor;
+import com.intellij.icons.AllIcons;
+import com.intellij.openapi.editor.SyntaxHighlighterColors;
+import com.intellij.openapi.editor.colors.EditorColorsManager;
+import com.intellij.openapi.editor.markup.TextAttributes;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.ui.*;
+import com.intellij.util.PlatformIcons;
+import com.intellij.xdebugger.impl.ui.XDebuggerUIConstants;
+import com.intellij.xdebugger.impl.ui.tree.ValueMarkup;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.awt.*;
+
+public class DebuggerTreeRenderer extends ColoredTreeCellRenderer {
+
+  private static final SimpleTextAttributes DEFAULT_ATTRIBUTES = new SimpleTextAttributes(Font.PLAIN, null);
+  private static final SimpleTextAttributes SPECIAL_NODE_ATTRIBUTES = new SimpleTextAttributes(Font.PLAIN, new JBColor(Color.lightGray, Gray._130));
+  private static final SimpleTextAttributes OBJECT_ID_HIGHLIGHT_ATTRIBUTES = new SimpleTextAttributes(Font.PLAIN, new JBColor(Color.lightGray, Gray._130));
+
+  public void customizeCellRenderer(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
+    final DebuggerTreeNodeImpl node = (DebuggerTreeNodeImpl) value;
+
+    if (node != null) {
+      final SimpleColoredText text = node.getText();
+      if (text != null) {
+        text.appendToComponent(this);
+      }
+      setIcon(node.getIcon());
+    }
+  }
+
+  @Nullable
+  public static Icon getDescriptorIcon(NodeDescriptorImpl descriptor) {
+    Icon nodeIcon = null;
+    if (descriptor instanceof ThreadGroupDescriptorImpl) {
+      nodeIcon = (((ThreadGroupDescriptorImpl)descriptor).isCurrent() ? AllIcons.Debugger.ThreadGroupCurrent : AllIcons.Debugger.ThreadGroup);
+    }
+    else if (descriptor instanceof ThreadDescriptorImpl) {
+      ThreadDescriptorImpl threadDescriptor = (ThreadDescriptorImpl)descriptor;
+      nodeIcon = threadDescriptor.getIcon();
+    }
+    else if (descriptor instanceof StackFrameDescriptorImpl) {
+      StackFrameDescriptorImpl stackDescriptor = (StackFrameDescriptorImpl)descriptor;
+      nodeIcon = stackDescriptor.getIcon();
+    }
+    else if (descriptor instanceof ValueDescriptorImpl) {
+      final ValueDescriptorImpl valueDescriptor = (ValueDescriptorImpl)descriptor;
+      if (valueDescriptor instanceof FieldDescriptorImpl && ((FieldDescriptorImpl)valueDescriptor).isStatic()) {
+        nodeIcon = PlatformIcons.FIELD_ICON;
+      }
+      else if (valueDescriptor.isArray()) {
+        nodeIcon = AllIcons.Debugger.Db_array;
+      }
+      else if (valueDescriptor.isPrimitive()) {
+        nodeIcon = AllIcons.Debugger.Db_primitive;
+      }
+      else {
+        if (valueDescriptor instanceof WatchItemDescriptor) {
+          nodeIcon = AllIcons.Debugger.Watch;
+        }
+        else {
+          nodeIcon = AllIcons.Debugger.Value;
+        }
+      }
+      final Icon valueIcon = valueDescriptor.getValueIcon();
+      if (nodeIcon != null && valueIcon != null) {
+        final RowIcon composite = new RowIcon(2);
+        composite.setIcon(nodeIcon, 0);
+        composite.setIcon(valueIcon, 1);
+        nodeIcon = composite;
+      }
+    }
+    else if (descriptor instanceof MessageDescriptor) {
+      MessageDescriptor messageDescriptor = (MessageDescriptor)descriptor;
+      if (messageDescriptor.getKind() == MessageDescriptor.ERROR) {
+        nodeIcon = XDebuggerUIConstants.ERROR_MESSAGE_ICON;
+      }
+      else if (messageDescriptor.getKind() == MessageDescriptor.INFORMATION) {
+        nodeIcon = XDebuggerUIConstants.INFORMATION_MESSAGE_ICON;
+      }
+      else if (messageDescriptor.getKind() == MessageDescriptor.SPECIAL) {
+        nodeIcon = null;
+      }
+    }
+    else if (descriptor instanceof StaticDescriptorImpl) {
+      nodeIcon = AllIcons.Nodes.Static;
+    }
+
+    return nodeIcon;
+  }
+
+  public static SimpleColoredText getDescriptorText(final DebuggerContextImpl debuggerContext, NodeDescriptorImpl descriptor, boolean multiline) {
+    return getDescriptorText(debuggerContext, descriptor, multiline, true);
+  }
+
+  public static SimpleColoredText getDescriptorTitle(final DebuggerContextImpl debuggerContext, NodeDescriptorImpl descriptor) {
+    return getDescriptorText(debuggerContext, descriptor, false, false);
+  }
+
+  private static SimpleColoredText getDescriptorText(final DebuggerContextImpl debuggerContext, final NodeDescriptorImpl descriptor, boolean multiline,
+                                                     boolean appendValue) {
+    SimpleColoredText descriptorText = new SimpleColoredText();
+
+    String text;
+    String nodeName;
+
+    if (descriptor == null) {
+      text = "";
+      nodeName = null;
+    }
+    else {
+      text = descriptor.getLabel();
+      nodeName = descriptor.getName();
+    }
+
+    if(text.equals(XDebuggerUIConstants.COLLECTING_DATA_MESSAGE)) {
+      descriptorText.append(XDebuggerUIConstants.COLLECTING_DATA_MESSAGE, XDebuggerUIConstants.COLLECTING_DATA_HIGHLIGHT_ATTRIBUTES);
+      return descriptorText;
+    }
+
+    if (descriptor instanceof ValueDescriptor) {
+      final ValueMarkup markup = ((ValueDescriptor)descriptor).getMarkup(debuggerContext.getDebugProcess());
+      if (markup != null) {
+        descriptorText.append("[" + markup.getText() + "] ", new SimpleTextAttributes(SimpleTextAttributes.STYLE_BOLD, markup.getColor()));
+      }
+    }
+
+    String[] strings = breakString(text, nodeName);
+
+    if (strings[0] != null) {
+      if (descriptor instanceof MessageDescriptor && ((MessageDescriptor)descriptor).getKind() == MessageDescriptor.SPECIAL) {
+        descriptorText.append(strings[0], SPECIAL_NODE_ATTRIBUTES);
+      }
+      else {
+        descriptorText.append(strings[0], DEFAULT_ATTRIBUTES);
+      }
+    }
+    if (strings[1] != null) {
+      descriptorText.append(strings[1], XDebuggerUIConstants.VALUE_NAME_ATTRIBUTES);
+    }
+    if (strings[2] != null) {
+      if (descriptor instanceof ValueDescriptorImpl) {
+        if(multiline && strings[2].indexOf('\n') >=0) {
+          strings = breakString(strings[2], "=");
+          if(strings[2] != null) {
+            strings[2] = strings[0] + strings[1] + "\n" + strings[2];
+          }
+        }
+
+
+        ValueDescriptorImpl valueDescriptor = (ValueDescriptorImpl)descriptor;
+        String valueLabel = valueDescriptor.getValueLabel();
+
+        strings = breakString(strings[2], valueLabel);
+        if (strings[0] != null) {
+          descriptorText.append(strings[0], DEFAULT_ATTRIBUTES);
+        }
+        if (appendValue && strings[1] != null) {
+          if(valueLabel != null && StringUtil.startsWithChar(valueLabel, '{') && valueLabel.indexOf('}') > 0 && !StringUtil.endsWithChar(valueLabel, '}')) {
+            int idx = valueLabel.indexOf('}');
+            String objectId = valueLabel.substring(0, idx + 1);
+            valueLabel = valueLabel.substring(idx + 1);
+            descriptorText.append(objectId, OBJECT_ID_HIGHLIGHT_ATTRIBUTES);
+          }
+
+          valueLabel =  DebuggerUtilsEx.truncateString(valueLabel);
+
+          final SimpleTextAttributes valueLabelAttribs;
+          if (valueDescriptor.isDirty()) {
+            valueLabelAttribs = XDebuggerUIConstants.CHANGED_VALUE_ATTRIBUTES;
+          }
+          else {
+            TextAttributes highlightingAttribs = null;
+            if (valueDescriptor.isNull()){
+              highlightingAttribs = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(SyntaxHighlighterColors.KEYWORD);
+            }
+            else if (valueDescriptor.isString()) {
+              highlightingAttribs = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(SyntaxHighlighterColors.STRING);
+            }
+            valueLabelAttribs = highlightingAttribs != null? SimpleTextAttributes.fromTextAttributes(highlightingAttribs) : DEFAULT_ATTRIBUTES;
+          }
+
+          final EvaluateException exception = descriptor.getEvaluateException();
+          if(exception != null) {
+            final String errorMessage = exception.getMessage();
+            if(valueLabel.endsWith(errorMessage)) {
+              appendValueTextWithEscapesRendering(descriptorText, valueLabel.substring(0, valueLabel.length() - errorMessage.length()), valueLabelAttribs);
+              descriptorText.append(errorMessage, XDebuggerUIConstants.EXCEPTION_ATTRIBUTES);
+            }
+            else {
+              appendValueTextWithEscapesRendering(descriptorText, valueLabel, valueLabelAttribs);
+              descriptorText.append(errorMessage, XDebuggerUIConstants.EXCEPTION_ATTRIBUTES);
+            }
+          }
+          else {
+            if(valueLabel.equals(XDebuggerUIConstants.COLLECTING_DATA_MESSAGE)) {
+              descriptorText.append(XDebuggerUIConstants.COLLECTING_DATA_MESSAGE, XDebuggerUIConstants.COLLECTING_DATA_HIGHLIGHT_ATTRIBUTES);
+            }
+            else {
+              appendValueTextWithEscapesRendering(descriptorText, valueLabel, valueLabelAttribs);
+            }
+          }
+        }
+      }
+      else {
+        descriptorText.append(strings[2], DEFAULT_ATTRIBUTES);
+      }
+    }
+
+    return descriptorText;
+  }
+
+  private static void appendValueTextWithEscapesRendering(SimpleColoredText descriptorText, String valueText, final SimpleTextAttributes attribs) {
+    SimpleTextAttributes escapeAttribs = null;
+    final StringBuilder buf = new StringBuilder();
+    boolean slashFound = false;
+    for (int idx= 0; idx < valueText.length(); idx++) {
+      final char ch = valueText.charAt(idx);
+      if (slashFound) {
+        slashFound = false;
+        if (ch == '\\' || ch == '\"' || ch == 'b'|| ch == 't'|| ch == 'n'|| ch == 'f'|| ch == 'r' ) {
+          if (buf.length() > 0) {
+            descriptorText.append(buf.toString(), attribs);
+            buf.setLength(0);
+          }
+
+          if (escapeAttribs == null) { // lazy init
+            final TextAttributes fromHighlighter = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(SyntaxHighlighterColors.VALID_STRING_ESCAPE);
+            if (fromHighlighter != null) {
+              escapeAttribs = SimpleTextAttributes.fromTextAttributes(fromHighlighter);
+            }
+            else {
+              escapeAttribs = DEFAULT_ATTRIBUTES.derive(SimpleTextAttributes.STYLE_BOLD, JBColor.GRAY, null, null);
+            }
+          }
+
+          if (ch != '\\' && ch != '\"') {
+            descriptorText.append("\\", escapeAttribs);
+          }
+          descriptorText.append(String.valueOf(ch), escapeAttribs);
+        }
+        else {
+          buf.append('\\').append(ch);
+        }
+      }
+      else {
+        if (ch == '\\') {
+          slashFound = true;
+        }
+        else {
+          buf.append(ch);
+        }
+      }
+    }
+    if (buf.length() > 0) {
+      descriptorText.append(buf.toString(), attribs);
+    }
+  }
+
+  private static String[] breakString(String source, String substr) {
+    if (substr != null && substr.length() > 0) {
+      int index = Math.max(source.indexOf(substr), 0);
+      String prefix = (index > 0) ? source.substring(0, index) : null;
+      index += substr.length();
+      String suffix = (index < source.length() - 1) ? source.substring(index) : null;
+      return new String[]{prefix, substr, suffix};
+    }
+    return new String[]{source, null, null};
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/FrameVariablesTree.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/FrameVariablesTree.java
new file mode 100644
index 0000000..ba9a9ff
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/FrameVariablesTree.java
@@ -0,0 +1,569 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class FrameDebuggerTree
+ * @author Jeka
+ */
+package com.intellij.debugger.ui.impl;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerInvocationUtil;
+import com.intellij.debugger.SourcePosition;
+import com.intellij.debugger.engine.DebuggerUtils;
+import com.intellij.debugger.engine.SuspendManager;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.debugger.engine.evaluation.TextWithImportsImpl;
+import com.intellij.debugger.engine.events.DebuggerCommandImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.debugger.jdi.LocalVariableProxyImpl;
+import com.intellij.debugger.jdi.StackFrameProxyImpl;
+import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
+import com.intellij.debugger.settings.ViewsGeneralSettings;
+import com.intellij.debugger.ui.impl.watch.*;
+import com.intellij.lang.java.JavaLanguage;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Computable;
+import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.Ref;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.*;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.util.text.CharArrayUtil;
+import com.intellij.util.ui.tree.TreeModelAdapter;
+import com.intellij.xdebugger.XDebuggerBundle;
+import com.sun.jdi.AbsentInformationException;
+import com.sun.jdi.ObjectCollectedException;
+import com.sun.jdi.Value;
+
+import javax.swing.event.TreeModelEvent;
+import javax.swing.tree.TreeModel;
+import javax.swing.tree.TreePath;
+import java.util.*;
+
+public class FrameVariablesTree extends DebuggerTree {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.impl.FrameDebuggerTree");
+  private boolean myAnyNewLocals;
+  private boolean myAutoWatchMode = false;
+
+  public FrameVariablesTree(Project project) {
+    super(project);
+    getEmptyText().setText(XDebuggerBundle.message("debugger.variables.not.available"));
+  }
+
+  public boolean isAutoWatchMode() {
+    return myAutoWatchMode;
+  }
+
+  public void setAutoVariablesMode(final boolean autoWatchMode) {
+    final boolean valueChanged = myAutoWatchMode != autoWatchMode;
+    myAutoWatchMode = autoWatchMode;
+    if (valueChanged) {
+      rebuild(getDebuggerContext());
+    }
+  }
+
+  protected void build(DebuggerContextImpl context) {
+    myAnyNewLocals = false;
+    buildWhenPaused(context, new RefreshFrameTreeCommand(context));
+  }
+
+  public void restoreNodeState(DebuggerTreeNodeImpl node) {
+    if (myAnyNewLocals) {
+      final NodeDescriptorImpl descriptor = node.getDescriptor();
+      final boolean isLocalVar = descriptor instanceof LocalVariableDescriptorImpl;
+      descriptor.myIsSelected &= isLocalVar;
+      // override this setting so that tree will scroll to new locals
+      descriptor.myIsVisible = isLocalVar && descriptor.myIsSelected;
+      if (!descriptor.myIsVisible) {
+        descriptor.putUserData(VISIBLE_RECT, null);
+      }
+    }
+    super.restoreNodeState(node);
+    if (myAnyNewLocals && node.getDescriptor().myIsExpanded) {
+      DebuggerTreeNodeImpl root = (DebuggerTreeNodeImpl)getMutableModel().getRoot();
+      scrollToVisible(root);
+    }
+  }
+
+
+  protected DebuggerCommandImpl getBuildNodeCommand(final DebuggerTreeNodeImpl node) {
+    if (node.getDescriptor() instanceof StackFrameDescriptorImpl) {
+      return new BuildFrameTreeVariablesCommand(node);
+    }
+    return super.getBuildNodeCommand(node);
+  }
+
+  private class BuildFrameTreeVariablesCommand extends BuildStackFrameCommand {
+    public BuildFrameTreeVariablesCommand(DebuggerTreeNodeImpl stackNode) {
+      super(stackNode);
+    }
+    
+    protected void buildVariables(final StackFrameDescriptorImpl stackDescriptor, final EvaluationContextImpl evaluationContext) throws EvaluateException {
+      final DebuggerContextImpl debuggerContext = getDebuggerContext();
+      final SourcePosition sourcePosition = debuggerContext.getSourcePosition();
+      if (sourcePosition == null) {
+        return;
+      }
+      try {
+        if (!ViewsGeneralSettings.getInstance().ENABLE_AUTO_EXPRESSIONS && !myAutoWatchMode) {
+          // optimization
+          super.buildVariables(stackDescriptor, evaluationContext);
+        }
+        else {
+          final Map<String, LocalVariableProxyImpl> visibleVariables = getVisibleVariables(stackDescriptor);
+          final EvaluationContextImpl evalContext = debuggerContext.createEvaluationContext();
+          final Pair<Set<String>, Set<TextWithImports>> usedVars =
+            ApplicationManager.getApplication().runReadAction(new Computable<Pair<Set<String>, Set<TextWithImports>>>() {
+              public Pair<Set<String>, Set<TextWithImports>> compute() {
+                return findReferencedVars(visibleVariables.keySet(), sourcePosition, evalContext);
+              }
+            });
+          // add locals
+          if (myAutoWatchMode) {
+            for (String var : usedVars.first) {
+              final LocalVariableDescriptorImpl descriptor = myNodeManager.getLocalVariableDescriptor(stackDescriptor, visibleVariables.get(var));
+              myChildren.add(myNodeManager.createNode(descriptor, evaluationContext));
+            }
+          }
+          else {
+            super.buildVariables(stackDescriptor, evaluationContext);
+          }
+          // add expressions
+          final EvaluationContextImpl evalContextCopy = evaluationContext.createEvaluationContext(evaluationContext.getThisObject());
+          evalContextCopy.setAutoLoadClasses(false);
+          for (TextWithImports text : usedVars.second) {
+            myChildren.add(myNodeManager.createNode(myNodeManager.getWatchItemDescriptor(stackDescriptor, text, null), evalContextCopy));
+          }
+        }
+      }
+      catch (EvaluateException e) {
+        if (e.getCause() instanceof AbsentInformationException) {
+          final StackFrameProxyImpl frame = stackDescriptor.getFrameProxy();
+          if (frame == null) {
+            throw e;
+          }
+          final Collection<Value> argValues = frame.getArgumentValues();
+          int index = 0;
+          for (Value argValue : argValues) {
+            final ArgumentValueDescriptorImpl descriptor = myNodeManager.getArgumentValueDescriptor(stackDescriptor, index++, argValue);
+            final DebuggerTreeNodeImpl variableNode = myNodeManager.createNode(descriptor, evaluationContext);
+            myChildren.add(variableNode);
+          }
+          myChildren.add(myNodeManager.createMessageNode(MessageDescriptor.LOCAL_VARIABLES_INFO_UNAVAILABLE));
+        }
+        else {
+          throw e;
+        }
+      }
+    }
+  }
+
+  private static Map<String, LocalVariableProxyImpl> getVisibleVariables(final StackFrameDescriptorImpl stackDescriptor) throws EvaluateException {
+    final StackFrameProxyImpl frame = stackDescriptor.getFrameProxy();
+    if (frame == null) {
+      return Collections.emptyMap();
+    }
+    final Map<String, LocalVariableProxyImpl> vars = new HashMap<String, LocalVariableProxyImpl>();
+    for (LocalVariableProxyImpl localVariableProxy : frame.visibleVariables()) {
+      vars.put(localVariableProxy.name(), localVariableProxy);
+    }
+    return vars;
+  }
+
+  private static boolean shouldSkipLine(final PsiFile file, Document doc, int line) {
+    final int start = doc.getLineStartOffset(line);
+    final int end = doc.getLineEndOffset(line);
+    final int _start = CharArrayUtil.shiftForward(doc.getCharsSequence(), start, " \n\t");
+    if (_start >= end) {
+      return true;
+    }
+    
+    TextRange alreadyChecked = null;
+    for (PsiElement elem = file.findElementAt(_start); elem != null && elem.getTextOffset() <= end && (alreadyChecked == null || !alreadyChecked .contains(elem.getTextRange())); elem = elem.getNextSibling()) {
+      for (PsiElement _elem = elem; _elem.getTextOffset() >= _start; _elem = _elem.getParent()) {
+        alreadyChecked = _elem.getTextRange();
+        
+        if (_elem instanceof PsiDeclarationStatement) {
+          final PsiElement[] declared = ((PsiDeclarationStatement)_elem).getDeclaredElements();
+          for (PsiElement declaredElement : declared) {
+            if (declaredElement instanceof PsiVariable) {
+              return false;
+            }
+          }
+        }
+        
+        if (_elem instanceof PsiJavaCodeReferenceElement) {
+          final PsiElement resolved = ((PsiJavaCodeReferenceElement)_elem).resolve();
+          if (resolved instanceof PsiVariable) {
+            return false;
+          }
+        }
+      }
+    }
+    return true;
+  }
+
+  private static Pair<Set<String>, Set<TextWithImports>> findReferencedVars(final Set<String> visibleVars,
+                                                                            final SourcePosition position,
+                                                                            EvaluationContextImpl evalContext) {
+    final int line = position.getLine();
+    if (line < 0) {
+      return new Pair<Set<String>, Set<TextWithImports>>(Collections.<String>emptySet(), Collections.<TextWithImports>emptySet());
+    }
+    final PsiFile positionFile = position.getFile();
+    if (!positionFile.getLanguage().isKindOf(JavaLanguage.INSTANCE)) {
+      return new Pair<Set<String>, Set<TextWithImports>>(visibleVars, Collections.<TextWithImports>emptySet());
+    }
+
+    final VirtualFile vFile = positionFile.getVirtualFile();
+    final Document doc = vFile != null? FileDocumentManager.getInstance().getDocument(vFile) : null;
+    if (doc == null || doc.getLineCount() == 0 || line > (doc.getLineCount() - 1)) {
+      return new Pair<Set<String>, Set<TextWithImports>>(Collections.<String>emptySet(), Collections.<TextWithImports>emptySet());
+    }
+    
+    final TextRange limit = calculateLimitRange(positionFile, doc, line);
+
+    int startLine = Math.max(limit.getStartOffset(), line - 1);
+    startLine = Math.min(startLine, limit.getEndOffset());
+    while (startLine > limit.getStartOffset() && shouldSkipLine(positionFile, doc, startLine)) {
+      startLine--;
+    }
+    final int startOffset = doc.getLineStartOffset(startLine);
+
+    int endLine = Math.min(line + 2, limit.getEndOffset());
+    while (endLine < limit.getEndOffset() && shouldSkipLine(positionFile, doc, endLine)) {
+      endLine++;
+    }
+    final int endOffset = doc.getLineEndOffset(endLine);
+
+    final TextRange lineRange = new TextRange(startOffset, endOffset);
+    if (!lineRange.isEmpty()) {
+      final int offset = CharArrayUtil.shiftForward(doc.getCharsSequence(), doc.getLineStartOffset(line), " \t");
+      PsiElement element = positionFile.findElementAt(offset);
+      if (element != null) {
+        PsiMethod method = PsiTreeUtil.getNonStrictParentOfType(element, PsiMethod.class);
+        if (method != null) {
+          element = method;
+        }
+        else {
+          PsiField field = PsiTreeUtil.getNonStrictParentOfType(element, PsiField.class);
+          if (field != null) {
+            element = field;
+          }
+          else {
+            final PsiClassInitializer initializer = PsiTreeUtil.getNonStrictParentOfType(element, PsiClassInitializer.class);
+            if (initializer != null) {
+              element = initializer;
+            }
+          }
+        }
+
+        //noinspection unchecked
+        if (element instanceof PsiCompiledElement) {
+          return new Pair<Set<String>, Set<TextWithImports>>(visibleVars, Collections.<TextWithImports>emptySet());
+        }
+        else {
+          final Set<String> vars = new HashSet<String>();
+          final Set<TextWithImports> expressions = new HashSet<TextWithImports>();
+          final PsiElementVisitor variablesCollector = new VariablesCollector(visibleVars, adjustRange(element, lineRange), expressions, vars, position, evalContext);
+          element.accept(variablesCollector);
+
+          return new Pair<Set<String>, Set<TextWithImports>>(vars, expressions);
+        }
+      }
+    }
+    return new Pair<Set<String>, Set<TextWithImports>>(Collections.<String>emptySet(), Collections.<TextWithImports>emptySet());
+  }
+
+  private static TextRange calculateLimitRange(final PsiFile file, final Document doc, final int line) {
+    final int offset = doc.getLineStartOffset(line);
+    if (offset > 0) {
+      for (PsiElement elem = file.findElementAt(offset); elem != null; elem = elem.getParent()) {
+        if (elem instanceof PsiMethod) {
+          final TextRange elemRange = elem.getTextRange();
+          return new TextRange(doc.getLineNumber(elemRange.getStartOffset()), doc.getLineNumber(elemRange.getEndOffset()));
+        }
+      }
+    }
+    return new TextRange(0, doc.getLineCount() - 1);
+  }
+
+  private static TextRange adjustRange(final PsiElement element, final TextRange originalRange) {
+    final Ref<TextRange> rangeRef = new Ref<TextRange>(originalRange);
+    element.accept(new JavaRecursiveElementVisitor() {
+      @Override public void visitExpressionStatement(final PsiExpressionStatement statement) {
+        final TextRange stRange = statement.getTextRange();
+        if (originalRange.intersects(stRange)) {
+          final TextRange currentRange = rangeRef.get();
+          final int start = Math.min(currentRange.getStartOffset(), stRange.getStartOffset());
+          final int end = Math.max(currentRange.getEndOffset(), stRange.getEndOffset());
+          rangeRef.set(new TextRange(start, end));
+        }
+      }
+    });
+    return rangeRef.get();
+  }
+
+  private class RefreshFrameTreeCommand extends RefreshDebuggerTreeCommand {
+    public RefreshFrameTreeCommand(DebuggerContextImpl context) {
+      super(context);
+    }
+
+    public void contextAction() throws Exception {
+      DebuggerTreeNodeImpl rootNode;
+
+      final DebuggerContextImpl debuggerContext = getDebuggerContext();
+      final ThreadReferenceProxyImpl currentThread = debuggerContext.getThreadProxy();
+      if (currentThread == null) {
+        return;
+      }
+
+      try {
+        StackFrameProxyImpl frame = debuggerContext.getFrameProxy();
+
+        if (frame != null) {
+          NodeManagerImpl nodeManager = getNodeFactory();
+          rootNode = nodeManager.createNode(nodeManager.getStackFrameDescriptor(null, frame), debuggerContext.createEvaluationContext());
+        }
+        else {
+          rootNode = getNodeFactory().getDefaultNode();
+          SuspendManager suspendManager = getSuspendContext().getDebugProcess().getSuspendManager();
+          try {
+            if (suspendManager.isSuspended(currentThread)) {
+              try {
+                if (currentThread.frameCount() == 0) {
+                  rootNode.add(MessageDescriptor.THREAD_IS_EMPTY);
+                }
+                else {
+                  rootNode.add(MessageDescriptor.DEBUG_INFO_UNAVAILABLE);
+                }
+              }
+              catch (EvaluateException e) {
+                rootNode.add(new MessageDescriptor(e.getMessage()));
+              }
+            }
+            else {
+              rootNode.add(MessageDescriptor.THREAD_IS_RUNNING);
+            }
+          }
+          catch (ObjectCollectedException e) {
+            rootNode.add(new MessageDescriptor(DebuggerBundle.message("label.thread.node.thread.collected", currentThread.name())));
+          }
+        }
+      }
+      catch (Exception ex) {
+        if (LOG.isDebugEnabled()) {
+          LOG.debug(ex);
+        }
+        rootNode = getNodeFactory().getDefaultNode();
+        rootNode.add(MessageDescriptor.DEBUG_INFO_UNAVAILABLE);
+      }
+
+      final DebuggerTreeNodeImpl rootNode1 = rootNode;
+      DebuggerInvocationUtil.swingInvokeLater(getProject(), new Runnable() {
+        public void run() {
+          getMutableModel().setRoot(rootNode1);
+          treeChanged();
+
+          final TreeModel model = getModel();
+          model.addTreeModelListener(new TreeModelAdapter() {
+            public void treeStructureChanged(TreeModelEvent e) {
+              final Object[] path = e.getPath();
+              if (path.length > 0 && path[path.length - 1] == rootNode1) {
+                // wait until rootNode1 (the root just set) becomes the root
+                model.removeTreeModelListener(this);
+                if (ViewsGeneralSettings.getInstance().AUTOSCROLL_TO_NEW_LOCALS) {
+                  autoscrollToNewLocals(rootNode1);
+                }
+                else {
+                  // should clear this flag, otherwise, if AUTOSCROLL_TO_NEW_LOCALS option turned
+                  // to true during the debug process, all these variables will be considered 'new'
+                  for (Enumeration children = rootNode1.rawChildren(); children.hasMoreElements();) {
+                    final DebuggerTreeNodeImpl child = (DebuggerTreeNodeImpl)children.nextElement();
+                    final NodeDescriptorImpl descriptor = child.getDescriptor();
+                    if (descriptor instanceof LocalVariableDescriptorImpl) {
+                      ((LocalVariableDescriptorImpl)descriptor).setNewLocal(false);
+                    }
+                  }
+                }
+              }
+            }
+          });
+        }
+
+        private void autoscrollToNewLocals(DebuggerTreeNodeImpl frameNode) {
+          final DebuggerSession debuggerSession = debuggerContext.getDebuggerSession();
+          final boolean isSteppingThrough = debuggerSession.isSteppingThrough(debuggerContext.getThreadProxy());
+          final List<DebuggerTreeNodeImpl> toClear = new ArrayList<DebuggerTreeNodeImpl>();
+          final List<DebuggerTreeNodeImpl> newLocalsToSelect = new ArrayList<DebuggerTreeNodeImpl>();
+
+          for (Enumeration e = frameNode.rawChildren(); e.hasMoreElements();) {
+            final DebuggerTreeNodeImpl child = (DebuggerTreeNodeImpl)e.nextElement();
+            final NodeDescriptorImpl descriptor = child.getDescriptor();
+            if (!(descriptor instanceof LocalVariableDescriptorImpl)) {
+              continue;
+            }
+            final LocalVariableDescriptorImpl localVariableDescriptor = (LocalVariableDescriptorImpl)descriptor;
+            if (isSteppingThrough && localVariableDescriptor.isNewLocal()) {
+              myAnyNewLocals = true;
+              newLocalsToSelect.add(child);
+            }
+            else {
+              toClear.add(child);
+            }
+            localVariableDescriptor.setNewLocal(false);
+          }
+
+          if (!newLocalsToSelect.isEmpty()) {
+            for (DebuggerTreeNodeImpl child : toClear) {
+              removeSelectionPath(new TreePath(child.getPath()));
+              child.getDescriptor().myIsSelected = false;
+            }
+            for (DebuggerTreeNodeImpl child : newLocalsToSelect) {
+              addSelectionPath(new TreePath(child.getPath()));
+              child.getDescriptor().myIsSelected = true;
+            }
+          }
+        }
+      });
+    }
+
+  }
+
+  private static class VariablesCollector extends JavaRecursiveElementVisitor {
+    private final Set<String> myVisibleLocals;
+    private final TextRange myLineRange;
+    private final Set<TextWithImports> myExpressions;
+    private final Set<String> myVars;
+    private final SourcePosition myPosition;
+    private final EvaluationContextImpl myEvalContext;
+    private final boolean myCollectExpressions;
+
+    public VariablesCollector(final Set<String> visibleLocals,
+                              final TextRange lineRange,
+                              final Set<TextWithImports> expressions,
+                              final Set<String> vars,
+                              SourcePosition position, EvaluationContextImpl evalContext) {
+      myVisibleLocals = visibleLocals;
+      myLineRange = lineRange;
+      myExpressions = expressions;
+      myVars = vars;
+      myPosition = position;
+      myEvalContext = evalContext;
+      myCollectExpressions = ViewsGeneralSettings.getInstance().ENABLE_AUTO_EXPRESSIONS;
+    }
+
+    @Override 
+    public void visitElement(final PsiElement element) {
+      if (myLineRange.intersects(element.getTextRange())) {
+        super.visitElement(element);
+      }
+    }
+
+    @Override 
+    public void visitMethodCallExpression(final PsiMethodCallExpression expression) {
+      if (myCollectExpressions) {
+        final PsiMethod psiMethod = expression.resolveMethod();
+        if (psiMethod != null && !DebuggerUtils.hasSideEffectsOrReferencesMissingVars(expression, myVisibleLocals)) {
+          myExpressions.add(new TextWithImportsImpl(expression));
+        }
+      }
+      super.visitMethodCallExpression(expression);
+    }
+
+    @Override 
+    public void visitReferenceExpression(final PsiReferenceExpression reference) {
+      if (myLineRange.intersects(reference.getTextRange())) {
+        final PsiElement psiElement = reference.resolve();
+        if (psiElement instanceof PsiVariable) {
+          final PsiVariable var = (PsiVariable)psiElement;
+          if (var instanceof PsiField) {
+            if (myCollectExpressions && !DebuggerUtils.hasSideEffectsOrReferencesMissingVars(reference, myVisibleLocals)) {
+              /*
+              if (var instanceof PsiEnumConstant && reference.getQualifier() == null) {
+                final PsiClass enumClass = ((PsiEnumConstant)var).getContainingClass();
+                if (enumClass != null) {
+                  final PsiExpression expression = JavaPsiFacade.getInstance(var.getProject()).getParserFacade().createExpressionFromText(enumClass.getName() + "." + var.getName(), var);
+                  final PsiReference ref = expression.getReference();
+                  if (ref != null) {
+                    ref.bindToElement(var);
+                    myExpressions.add(new TextWithImportsImpl(expression));
+                  }
+                }
+              }                                        
+              else {
+                myExpressions.add(new TextWithImportsImpl(reference));
+              }
+              */
+              final PsiModifierList modifierList = var.getModifierList();
+              boolean isConstant = (var instanceof PsiEnumConstant) || 
+                                   (modifierList != null && modifierList.hasModifierProperty(PsiModifier.STATIC) && modifierList.hasModifierProperty(PsiModifier.FINAL));
+              if (!isConstant) {
+                myExpressions.add(new TextWithImportsImpl(reference));
+              }
+            }
+          }
+          else {
+            if (myVisibleLocals.contains(var.getName())) {
+              myVars.add(var.getName());
+            }
+          }
+        }
+      }
+      super.visitReferenceExpression(reference);
+    }
+
+    @Override 
+    public void visitArrayAccessExpression(final PsiArrayAccessExpression expression) {
+      if (myCollectExpressions && !DebuggerUtils.hasSideEffectsOrReferencesMissingVars(expression, myVisibleLocals)) {
+        myExpressions.add(new TextWithImportsImpl(expression));
+      }
+      super.visitArrayAccessExpression(expression);
+    }
+
+    @Override 
+    public void visitParameter(final PsiParameter parameter) {
+      processVariable(parameter);
+      super.visitParameter(parameter);
+    }
+
+    @Override 
+    public void visitLocalVariable(final PsiLocalVariable variable) {
+      processVariable(variable);
+      super.visitLocalVariable(variable);
+    }
+
+    private void processVariable(final PsiVariable variable) {
+      if (myLineRange.intersects(variable.getTextRange()) && myVisibleLocals.contains(variable.getName())) {
+        myVars.add(variable.getName());
+      }
+    }
+
+    @Override 
+    public void visitClass(final PsiClass aClass) {
+      // Do not step in to local and anonymous classes...
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/FramesList.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/FramesList.java
new file mode 100644
index 0000000..9967b70
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/FramesList.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.impl;
+
+import com.intellij.debugger.ui.impl.watch.StackFrameDescriptorImpl;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Comparing;
+import com.intellij.xdebugger.impl.frame.DebuggerFramesList;
+import com.sun.jdi.Method;
+
+import javax.swing.*;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: Dec 7, 2006
+ */
+public class FramesList extends DebuggerFramesList {
+  private volatile Method mySelectedMethod = null;
+
+  public FramesList(Project project) {
+    super(project);
+    doInit();
+  }
+
+  protected FramesListRenderer createListRenderer() {
+    return new FramesListRenderer();
+  }
+
+  protected void onFrameChanged(final Object selectedValue) {
+    final StackFrameDescriptorImpl descriptor = selectedValue instanceof StackFrameDescriptorImpl? (StackFrameDescriptorImpl)selectedValue : null;
+    final Method newMethod = descriptor != null? descriptor.getMethod() : null;
+    if (!Comparing.equal(mySelectedMethod, newMethod)) {
+      SwingUtilities.invokeLater(new Runnable() {
+        public void run() {
+          repaint();
+        }
+      });
+    }
+    mySelectedMethod = newMethod;
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/FramesListRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/FramesListRenderer.java
new file mode 100644
index 0000000..c6e6228
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/FramesListRenderer.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2000-2012 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.debugger.ui.impl;
+
+import com.intellij.debugger.ui.impl.watch.StackFrameDescriptorImpl;
+import com.intellij.ui.JBColor;
+import com.intellij.xdebugger.impl.ui.tree.ValueMarkup;
+import com.intellij.openapi.editor.colors.EditorColorsManager;
+import com.intellij.openapi.editor.colors.EditorColorsScheme;
+import com.intellij.openapi.util.Comparing;
+import com.intellij.ui.ColoredListCellRenderer;
+import com.intellij.ui.SimpleTextAttributes;
+import com.intellij.util.ui.UIUtil;
+import com.intellij.xdebugger.ui.DebuggerColors;
+import com.sun.jdi.Method;
+
+import javax.swing.*;
+import javax.swing.border.MatteBorder;
+import java.awt.*;
+
+class FramesListRenderer extends ColoredListCellRenderer {
+  private final EditorColorsScheme myColorScheme;
+
+  public FramesListRenderer() {
+    myColorScheme = EditorColorsManager.getInstance().getGlobalScheme();
+  }
+
+  protected void customizeCellRenderer(final JList list, final Object item, final int index, final boolean selected, final boolean hasFocus) {
+    if (!(item instanceof StackFrameDescriptorImpl)) {
+      append(item.toString(), SimpleTextAttributes.GRAYED_ATTRIBUTES);
+    }
+    else {
+      final StackFrameDescriptorImpl descriptor = (StackFrameDescriptorImpl)item;
+      setIcon(descriptor.getIcon());
+      final Object selectedValue = list.getSelectedValue();
+      final boolean shouldHighlightAsRecursive = (selectedValue instanceof StackFrameDescriptorImpl) && 
+                                                 isOccurrenceOfSelectedFrame((StackFrameDescriptorImpl)selectedValue, descriptor);
+
+      final ValueMarkup markup = descriptor.getValueMarkup();
+      if (markup != null) {
+        append("["+ markup.getText() + "] ", new SimpleTextAttributes(SimpleTextAttributes.STYLE_BOLD, markup.getColor()));
+      }
+
+      boolean needSeparator = false;
+      if (index > 0) {
+        final int currentFrameIndex = descriptor.getUiIndex();
+        final Object elementAt = list.getModel().getElementAt(index - 1);
+        if (elementAt instanceof StackFrameDescriptorImpl) {
+          StackFrameDescriptorImpl previousDescriptor = (StackFrameDescriptorImpl)elementAt;
+          final int previousFrameIndex = previousDescriptor.getUiIndex();
+          needSeparator = (currentFrameIndex - previousFrameIndex != 1);
+        }
+      }
+
+      if (selected) {
+        setBackground(UIUtil.getListSelectionBackground());
+      }
+      else {
+        Color bg = descriptor.getBackgroundColor();
+        if (bg == null) bg = UIUtil.getListBackground();
+        if (shouldHighlightAsRecursive) bg = myColorScheme.getColor(DebuggerColors.RECURSIVE_CALL_ATTRIBUTES);
+        setBackground(bg);
+      }
+
+      if (needSeparator) {
+        final MatteBorder border = BorderFactory.createMatteBorder(1, 0, 0, 0, JBColor.GRAY);
+        setBorder(border);
+      }
+      else {
+        setBorder(null);
+      }
+      
+      final String label = descriptor.getLabel();
+      final int openingBrace = label.indexOf("{");
+      final int closingBrace = (openingBrace < 0) ? -1 : label.indexOf("}");
+      final SimpleTextAttributes attributes = getAttributes(descriptor);
+      if (openingBrace < 0 || closingBrace < 0) {
+        append(label, attributes);
+      }
+      else {
+        append(label.substring(0, openingBrace - 1), attributes);
+        append(" (" + label.substring(openingBrace + 1, closingBrace) + ")", SimpleTextAttributes.GRAY_ITALIC_ATTRIBUTES);
+
+        append(label.substring(closingBrace + 1, label.length()), attributes);
+        if (shouldHighlightAsRecursive && descriptor.isRecursiveCall()) {
+          append(" [" + descriptor.getOccurrenceIndex() + "]", SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES);
+        }
+      }
+    }
+  }
+
+  private static boolean isOccurrenceOfSelectedFrame(final StackFrameDescriptorImpl selectedDescriptor, StackFrameDescriptorImpl descriptor) {
+    final Method currentMethod = descriptor.getMethod();
+    if (currentMethod != null) {
+      if (selectedDescriptor != null) {
+        final Method selectedMethod = selectedDescriptor.getMethod();
+        if (selectedMethod != null) {
+          if (Comparing.equal(selectedMethod, currentMethod)) {
+            return true;
+          }
+        }
+      }
+    }
+    return false;
+  }
+
+  private static SimpleTextAttributes getAttributes(final StackFrameDescriptorImpl descriptor) {
+    if (descriptor.isSynthetic() || descriptor.isInLibraryContent()) {
+      return SimpleTextAttributes.GRAYED_ATTRIBUTES;
+    }
+    return SimpleTextAttributes.SIMPLE_CELL_ATTRIBUTES;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/InspectDebuggerTree.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/InspectDebuggerTree.java
new file mode 100644
index 0000000..275e08b
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/InspectDebuggerTree.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.impl;
+
+import com.intellij.debugger.DebuggerInvocationUtil;
+import com.intellij.debugger.actions.DebuggerActions;
+import com.intellij.debugger.engine.events.DebuggerContextCommandImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.ui.impl.watch.DebuggerTree;
+import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
+import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl;
+import com.intellij.openapi.actionSystem.ActionGroup;
+import com.intellij.openapi.actionSystem.ActionManager;
+import com.intellij.openapi.actionSystem.ActionPopupMenu;
+import com.intellij.openapi.project.Project;
+import com.intellij.ui.PopupHandler;
+
+import java.awt.*;
+
+public class InspectDebuggerTree extends DebuggerTree{
+  private NodeDescriptorImpl myInspectDescriptor;
+
+  public InspectDebuggerTree(Project project) {
+    super(project);
+
+    final PopupHandler popupHandler = new PopupHandler() {
+      public void invokePopup(Component comp, int x, int y) {
+        ActionPopupMenu popupMenu = createPopupMenu();
+        if (popupMenu != null) {
+          myTipManager.registerPopup(popupMenu.getComponent()).show(comp, x, y);
+        }
+      }
+    };
+    addMouseListener(popupHandler);
+
+    new ValueNodeDnD(this, project);
+  }
+
+  public static ActionPopupMenu createPopupMenu() {
+    ActionGroup group = (ActionGroup)ActionManager.getInstance().getAction(DebuggerActions.INSPECT_PANEL_POPUP);
+    return ActionManager.getInstance().createActionPopupMenu(DebuggerActions.INSPECT_PANEL_POPUP, group);
+  }
+
+  protected void build(DebuggerContextImpl context) {
+    updateNode(context);
+  }
+
+  public void setInspectDescriptor(NodeDescriptorImpl inspectDescriptor) {
+    myInspectDescriptor = inspectDescriptor;
+  }
+
+  public NodeDescriptorImpl getInspectDescriptor() {
+    return myInspectDescriptor;
+  }
+
+
+
+  private void updateNode(final DebuggerContextImpl context) {
+    context.getDebugProcess().getManagerThread().schedule(new DebuggerContextCommandImpl(context) {
+      public void threadAction() {
+        final DebuggerTreeNodeImpl node = getNodeFactory().createNode(myInspectDescriptor, context.createEvaluationContext());
+
+        DebuggerInvocationUtil.swingInvokeLater(getProject(), new Runnable() {
+          public void run() {
+            DebuggerTreeNodeImpl root = (DebuggerTreeNodeImpl) getModel().getRoot();
+            root.removeAllChildren();
+
+            root.add(node);
+            treeChanged();
+            root.getTree().expandRow(0);
+          }
+        });
+      }
+    });
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/InspectDialog.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/InspectDialog.java
new file mode 100644
index 0000000..bc2f818
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/InspectDialog.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.impl;
+
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerContextListener;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.debugger.impl.DebuggerStateManager;
+import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
+
+import javax.swing.*;
+
+public class InspectDialog extends DialogWrapper implements DebuggerContextListener {
+  private InspectPanel myInspectView;
+  private final DebuggerContextImpl myDebuggerContext;
+
+  public InspectDialog(Project project, DebuggerStateManager stateManager, String title, NodeDescriptorImpl inspectDescriptor) {
+    super(project, true);
+    setTitle(title);
+    setModal(false);
+
+    myDebuggerContext = stateManager.getContext();
+
+    myInspectView = new InspectPanel(project, myDebuggerContext.getDebuggerSession().getContextManager(), inspectDescriptor);
+    myInspectView.setBorder(BorderFactory.createEtchedBorder());
+
+    init();
+
+    myDebuggerContext.getDebuggerSession().getContextManager().addListener(this);
+    getInspectView().rebuildIfVisible(DebuggerSession.EVENT_CONTEXT);
+  }
+
+  protected JComponent createCenterPanel() {
+    return myInspectView;
+  }
+
+  protected JComponent createSouthPanel() {
+    return null;
+  }
+
+  public void dispose() {
+    myDebuggerContext.getDebuggerSession().getContextManager().removeListener(this);
+    if (myInspectView != null) {
+      myInspectView.dispose();
+      myInspectView = null;
+    }
+    super.dispose();
+  }
+
+  protected String getDimensionServiceKey(){
+    return "#com.intellij.debugger.ui.impl.InspectDialog";
+  }
+
+  public InspectPanel getInspectView() {
+    return myInspectView;
+  }
+
+  public void changeEvent(DebuggerContextImpl newContext, int event) {
+    if(event == DebuggerSession.EVENT_DETACHED) {
+      close(CANCEL_EXIT_CODE);
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/InspectPanel.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/InspectPanel.java
new file mode 100644
index 0000000..c5fe2e0
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/InspectPanel.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class InspectPanel
+ * @author Jeka
+ */
+package com.intellij.debugger.ui.impl;
+
+import com.intellij.debugger.actions.DebuggerAction;
+import com.intellij.debugger.actions.DebuggerActions;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.debugger.impl.DebuggerStateManager;
+import com.intellij.debugger.ui.impl.watch.DebuggerTree;
+import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl;
+import com.intellij.openapi.actionSystem.ActionPopupMenu;
+import com.intellij.openapi.actionSystem.CommonShortcuts;
+import com.intellij.openapi.project.Project;
+import com.intellij.ui.ScrollPaneFactory;
+import org.jetbrains.annotations.NotNull;
+
+import java.awt.*;
+
+public class InspectPanel extends DebuggerTreePanel {
+  public InspectPanel(Project project, DebuggerStateManager stateManager, @NotNull NodeDescriptorImpl inspectDescriptor) {
+    super(project, stateManager);
+
+    getInspectTree().setInspectDescriptor(inspectDescriptor);
+
+    add(ScrollPaneFactory.createScrollPane(getInspectTree()), BorderLayout.CENTER);
+    registerDisposable(DebuggerAction.installEditAction(getInspectTree(), DebuggerActions.EDIT_NODE_SOURCE));
+
+    overrideShortcut(getInspectTree(), DebuggerActions.COPY_VALUE, CommonShortcuts.getCopy());
+    setUpdateEnabled(true);
+  }
+
+  protected void changeEvent(DebuggerContextImpl newContext, int event) {
+    if (event != DebuggerSession.EVENT_THREADS_REFRESH) {
+      super.changeEvent(newContext, event);
+    }
+  }
+
+  protected DebuggerTree createTreeView() {
+    return new InspectDebuggerTree(getProject());
+  }
+
+  protected ActionPopupMenu createPopupMenu() {
+    return InspectDebuggerTree.createPopupMenu();
+  }
+
+  public InspectDebuggerTree getInspectTree() {
+    return (InspectDebuggerTree)getTree();
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/MainWatchPanel.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/MainWatchPanel.java
new file mode 100644
index 0000000..2034938
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/MainWatchPanel.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/**
+ * created at Dec 17, 2001
+ * @author Jeka
+ */
+package com.intellij.debugger.ui.impl;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.actions.AddToWatchActionHandler;
+import com.intellij.debugger.actions.DebuggerActions;
+import com.intellij.debugger.engine.evaluation.CodeFragmentKind;
+import com.intellij.debugger.engine.evaluation.DefaultCodeFragmentFactory;
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.debugger.engine.evaluation.TextWithImportsImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerStateManager;
+import com.intellij.debugger.impl.PositionUtil;
+import com.intellij.debugger.ui.DebuggerExpressionComboBox;
+import com.intellij.debugger.ui.impl.watch.DebuggerTreeInplaceEditor;
+import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
+import com.intellij.debugger.ui.impl.watch.WatchItemDescriptor;
+import com.intellij.ide.DataManager;
+import com.intellij.ide.dnd.DnDEvent;
+import com.intellij.ide.dnd.DnDManager;
+import com.intellij.ide.dnd.DnDNativeTarget;
+import com.intellij.ide.dnd.DropActionHandler;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.SystemInfo;
+import com.intellij.ui.*;
+import com.intellij.ui.border.CustomLineBorder;
+import com.intellij.xdebugger.impl.actions.XDebuggerActions;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+
+public class MainWatchPanel extends WatchPanel implements DataProvider {
+
+  public MainWatchPanel(Project project, DebuggerStateManager stateManager) {
+    super(project,stateManager);
+    final WatchDebuggerTree watchTree = getWatchTree();
+
+    final AnAction removeWatchesAction = ActionManager.getInstance().getAction(DebuggerActions.REMOVE_WATCH);
+    removeWatchesAction.registerCustomShortcutSet(CommonShortcuts.DELETE, watchTree);
+
+    final AnAction newWatchAction  = ActionManager.getInstance().getAction(DebuggerActions.NEW_WATCH);
+    newWatchAction.registerCustomShortcutSet(CommonShortcuts.INSERT, watchTree);
+
+    final ClickListener mouseListener = new DoubleClickListener() {
+      @Override
+      protected boolean onDoubleClick(MouseEvent e) {
+        AnAction editWatchAction = ActionManager.getInstance().getAction(DebuggerActions.EDIT_WATCH);
+        Presentation presentation = editWatchAction.getTemplatePresentation().clone();
+        DataContext context = DataManager.getInstance().getDataContext(watchTree);
+
+        AnActionEvent actionEvent = new AnActionEvent(null, context, "WATCH_TREE", presentation, ActionManager.getInstance(), 0);
+        editWatchAction.actionPerformed(actionEvent);
+        return true;
+      }
+    };
+    ListenerUtil.addClickListener(watchTree, mouseListener);
+
+    final AnAction editWatchAction  = ActionManager.getInstance().getAction(DebuggerActions.EDIT_WATCH);
+    editWatchAction.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0)), watchTree);
+    registerDisposable(new Disposable() {
+      public void dispose() {
+        ListenerUtil.removeClickListener(watchTree, mouseListener);
+        removeWatchesAction.unregisterCustomShortcutSet(watchTree);
+        newWatchAction.unregisterCustomShortcutSet(watchTree);
+        editWatchAction.unregisterCustomShortcutSet(watchTree);
+      }
+    });
+
+    DnDManager.getInstance().registerTarget(new DnDNativeTarget() {
+      public boolean update(final DnDEvent aEvent) {
+        Object object = aEvent.getAttachedObject();
+        if (object == null) return true;
+
+        String add = DebuggerBundle.message("watchs.add.text");
+
+        if (object.getClass().isArray()) {
+          Class<?> type = object.getClass().getComponentType();
+          if (DebuggerTreeNodeImpl.class.isAssignableFrom(type)) {
+            aEvent.setHighlighting(myTree, DnDEvent.DropTargetHighlightingType.RECTANGLE | DnDEvent.DropTargetHighlightingType.TEXT);
+            aEvent.setDropPossible(add, new DropActionHandler() {
+              public void performDrop(final DnDEvent aEvent) {
+                addWatchesFrom((DebuggerTreeNodeImpl[])aEvent.getAttachedObject());
+              }
+            });
+          }
+        } else if (object instanceof EventInfo) {
+          EventInfo info = (EventInfo)object;
+          final String text = info.getTextForFlavor(DataFlavor.stringFlavor);
+          if (text != null) {
+            aEvent.setHighlighting(myTree, DnDEvent.DropTargetHighlightingType.RECTANGLE | DnDEvent.DropTargetHighlightingType.TEXT);
+            aEvent.setDropPossible(add, new DropActionHandler() {
+              public void performDrop(final DnDEvent aEvent) {
+                addWatchesFrom(text);
+              }
+            });
+          }
+        }
+
+        return true;
+      }
+
+      public void drop(final DnDEvent aEvent) {
+      }
+
+      public void cleanUpOnLeave() {
+      }
+
+      public void updateDraggedImage(final Image image, final Point dropPoint, final Point imageOffset) {
+      }
+    }, myTree);
+  }
+
+  private void addWatchesFrom(final DebuggerTreeNodeImpl[] nodes) {
+    AddToWatchActionHandler.addFromNodes(getContext(), this, nodes);
+  }
+
+  private void addWatchesFrom(String text) {
+    AddToWatchActionHandler.doAddWatch(this, new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, text), null);
+  }
+
+  protected ActionPopupMenu createPopupMenu() {
+    ActionGroup group = (ActionGroup)ActionManager.getInstance().getAction(DebuggerActions.WATCH_PANEL_POPUP);
+    ActionPopupMenu popupMenu = ActionManager.getInstance().createActionPopupMenu(DebuggerActions.WATCH_PANEL_POPUP, group);
+    return popupMenu;
+  }
+
+  public void newWatch() {
+    final DebuggerTreeNodeImpl node = getWatchTree().addWatch(new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, ""), null);
+    editNode(node);
+  }
+
+  public void editNode(final DebuggerTreeNodeImpl node) {
+    final DebuggerContextImpl context = getContext();
+    final DebuggerExpressionComboBox comboBox = new DebuggerExpressionComboBox(getProject(), PositionUtil.getContextElement(context), "evaluation",
+                                                                               DefaultCodeFragmentFactory.getInstance());
+    comboBox.setText(((WatchItemDescriptor)node.getDescriptor()).getEvaluationText());
+    comboBox.selectAll();
+
+    DebuggerTreeInplaceEditor editor = new DebuggerTreeInplaceEditor(node) {
+      public JComponent createInplaceEditorComponent() {
+        return comboBox;
+      }
+
+      public JComponent getPreferredFocusedComponent() {
+        return comboBox.getPreferredFocusedComponent();
+      }
+
+      public Editor getEditor() {
+        return comboBox.getEditor();
+      }
+
+      public JComponent getEditorComponent() {
+        return comboBox.getEditorComponent();
+      }
+
+      public void doOKAction() {
+        if (comboBox.isPopupVisible()) {
+          comboBox.selectPopupValue();
+        }
+
+        TextWithImports text = comboBox.getText();
+        WatchDebuggerTree.setWatchNodeText(node, text);
+        comboBox.addRecent(text);
+        try {
+          super.doOKAction();
+        }
+        finally {
+          comboBox.dispose();
+        }
+      }
+
+      public void cancelEditing() {
+        comboBox.setPopupVisible(false);
+
+        try {
+          super.cancelEditing();
+        }
+        finally {
+          comboBox.dispose();
+        }
+      }
+    };
+    editor.show();
+  }
+
+  @Override
+  protected JComponent createTreePanel(final WatchDebuggerTree tree) {
+    final ToolbarDecorator decorator = ToolbarDecorator.createDecorator(tree);
+    decorator.setAddAction(new AnActionButtonRunnable() {
+      @Override
+      public void run(AnActionButton button) {
+        executeAction(DebuggerActions.NEW_WATCH, tree);
+      }
+    });
+    // TODO[den]: add "Add to watches action" on Mac
+    if (!SystemInfo.isMac) {
+      decorator.addExtraAction(AnActionButton.fromAction(ActionManager.getInstance().getAction(XDebuggerActions.ADD_TO_WATCH)));
+    }
+    decorator.setRemoveAction(new AnActionButtonRunnable() {
+      @Override
+      public void run(AnActionButton button) {
+        executeAction(DebuggerActions.REMOVE_WATCH, tree);
+      }
+    });
+    CustomLineBorder border = new CustomLineBorder(CaptionPanel.CNT_ACTIVE_BORDER_COLOR,
+                                                   SystemInfo.isMac ? 1 : 0, 0,
+                                                   SystemInfo.isMac ? 0 : 1, 0);
+    decorator.setToolbarBorder(border);
+    final JPanel panel = decorator.createPanel();
+    panel.setBorder(null);
+    return panel;
+  }
+
+  private static void executeAction(final String watch, final WatchDebuggerTree tree) {
+    AnAction action = ActionManager.getInstance().getAction(watch);
+    Presentation presentation = action.getTemplatePresentation().clone();
+    DataContext context = DataManager.getInstance().getDataContext(tree);
+
+    AnActionEvent actionEvent =
+      new AnActionEvent(null, context, ActionPlaces.DEBUGGER_TOOLBAR, presentation, ActionManager.getInstance(), 0);
+    action.actionPerformed(actionEvent);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/ThreadsDebuggerTree.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/ThreadsDebuggerTree.java
new file mode 100644
index 0000000..18f71d5
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/ThreadsDebuggerTree.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.impl;
+
+import com.intellij.debugger.DebuggerInvocationUtil;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.SuspendContextImpl;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.engine.events.DebuggerCommandImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.debugger.jdi.StackFrameProxyImpl;
+import com.intellij.debugger.jdi.ThreadGroupReferenceProxyImpl;
+import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
+import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
+import com.intellij.debugger.settings.ThreadsViewSettings;
+import com.intellij.debugger.ui.impl.watch.*;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.util.ui.tree.TreeModelAdapter;
+import com.intellij.xdebugger.XDebuggerBundle;
+
+import javax.swing.*;
+import javax.swing.event.TreeModelEvent;
+import javax.swing.tree.TreePath;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+
+/**
+ * User: lex
+ * Date: Sep 26, 2003
+ * Time: 5:57:58 PM
+ */
+public class ThreadsDebuggerTree extends DebuggerTree {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.impl.ThreadsDebuggerTree");
+
+  public ThreadsDebuggerTree(Project project) {
+    super(project);
+    getEmptyText().setText(XDebuggerBundle.message("debugger.threads.not.available"));
+  }
+
+  protected NodeManagerImpl createNodeManager(Project project) {
+    return new NodeManagerImpl(project, this) {
+      public String getContextKey(StackFrameProxyImpl frame) {
+        return "ThreadsView";
+      }
+    };
+  }
+
+  protected boolean isExpandable(DebuggerTreeNodeImpl node) {
+    NodeDescriptorImpl descriptor = node.getDescriptor();
+    if(descriptor instanceof StackFrameDescriptorImpl) {
+      return false;
+    }
+    return descriptor.isExpandable();
+  }
+
+  protected void build(DebuggerContextImpl context) {
+    DebuggerSession debuggerSession = context.getDebuggerSession();
+    final RefreshThreadsTreeCommand command = new RefreshThreadsTreeCommand(debuggerSession);
+    
+    final int state = debuggerSession.getState();
+    if (ApplicationManager.getApplication().isUnitTestMode() || state == DebuggerSession.STATE_PAUSED || state == DebuggerSession.STATE_RUNNING) {
+      showMessage(MessageDescriptor.EVALUATING);
+      context.getDebugProcess().getManagerThread().schedule(command);
+    }
+    else {
+      showMessage(debuggerSession.getStateDescription());
+    }
+  }
+
+  private class RefreshThreadsTreeCommand extends DebuggerCommandImpl{
+    private final DebuggerSession mySession;
+
+    public RefreshThreadsTreeCommand(DebuggerSession session) {
+      mySession = session;
+    }
+
+    protected void action() throws Exception {
+      final DebuggerTreeNodeImpl root = getNodeFactory().getDefaultNode();
+
+      final DebugProcessImpl debugProcess = mySession.getProcess();
+      if(debugProcess == null || !debugProcess.isAttached()) {
+        return;
+      }
+      final DebuggerContextImpl context = mySession.getContextManager().getContext();
+      final SuspendContextImpl suspendContext = context.getSuspendContext();
+      final ThreadReferenceProxyImpl suspendContextThread = suspendContext != null? suspendContext.getThread() : null;
+      
+      final boolean showGroups = ThreadsViewSettings.getInstance().SHOW_THREAD_GROUPS;
+      try {
+        final ThreadReferenceProxyImpl currentThread = ThreadsViewSettings.getInstance().SHOW_CURRENT_THREAD ? suspendContextThread : null;
+        final VirtualMachineProxyImpl vm = debugProcess.getVirtualMachineProxy();
+
+        final EvaluationContextImpl evaluationContext = suspendContext != null? getDebuggerContext().createEvaluationContext() : null;
+        final NodeManagerImpl nodeManager = getNodeFactory();
+
+        if (showGroups) {
+          ThreadGroupReferenceProxyImpl topCurrentGroup = null;
+
+          if (currentThread != null) {
+            topCurrentGroup = currentThread.threadGroupProxy();
+            if (topCurrentGroup != null) {
+              for(ThreadGroupReferenceProxyImpl parentGroup = topCurrentGroup.parent(); parentGroup != null; parentGroup = parentGroup.parent()) {
+                topCurrentGroup = parentGroup;
+              }
+            }
+
+            if(topCurrentGroup != null){
+              root.add(nodeManager.createNode(nodeManager.getThreadGroupDescriptor(null, topCurrentGroup), evaluationContext));
+            }
+            else {
+              root.add(nodeManager.createNode(nodeManager.getThreadDescriptor(null, currentThread), evaluationContext));
+            }
+          }
+
+          for (ThreadGroupReferenceProxyImpl group : vm.topLevelThreadGroups()) {
+            if (group != topCurrentGroup) {
+              DebuggerTreeNodeImpl threadGroup = nodeManager.createNode(nodeManager.getThreadGroupDescriptor(null, group), evaluationContext);
+              root.add(threadGroup);
+            }
+          }
+        }
+        else {
+          // do not show thread groups
+          if (currentThread != null) {
+            root.insert(nodeManager.createNode(nodeManager.getThreadDescriptor(null, currentThread), evaluationContext), 0);
+          }
+          List<ThreadReferenceProxyImpl> allThreads = new ArrayList<ThreadReferenceProxyImpl>(vm.allThreads());
+          Collections.sort(allThreads, ThreadReferenceProxyImpl.ourComparator);
+
+          for (ThreadReferenceProxyImpl threadProxy : allThreads) {
+            if (threadProxy.equals(currentThread)) {
+              continue;
+            }
+            root.add(nodeManager.createNode(nodeManager.getThreadDescriptor(null, threadProxy), evaluationContext));
+          }
+        }
+      }
+      catch (Exception ex) {
+        root.add( MessageDescriptor.DEBUG_INFO_UNAVAILABLE);
+        if (LOG.isDebugEnabled()) {
+          LOG.debug(ex);
+        }
+      }
+
+      final boolean hasThreadToSelect = suspendContextThread != null; // thread can be null if pause was pressed
+      final List<ThreadGroupReferenceProxyImpl> groups;
+      if (hasThreadToSelect && showGroups) {
+        groups = new ArrayList<ThreadGroupReferenceProxyImpl>();
+        for(ThreadGroupReferenceProxyImpl group = suspendContextThread.threadGroupProxy(); group != null; group = group.parent()) {
+          groups.add(group);
+        }
+        Collections.reverse(groups);
+      }
+      else {
+        groups = Collections.emptyList();
+      }
+
+      DebuggerInvocationUtil.swingInvokeLater(getProject(), new Runnable() {
+        public void run() {
+          getMutableModel().setRoot(root);
+          treeChanged();
+          if (hasThreadToSelect) {
+            selectThread(groups, suspendContextThread, true);
+          }
+        }
+      });
+    }
+
+    private void selectThread(final List<ThreadGroupReferenceProxyImpl> pathToThread, final ThreadReferenceProxyImpl thread, final boolean expand) {
+      LOG.assertTrue(SwingUtilities.isEventDispatchThread());
+      class MyTreeModelAdapter extends TreeModelAdapter {
+        private void structureChanged(DebuggerTreeNodeImpl node) {
+          for(Enumeration enumeration = node.children(); enumeration.hasMoreElements(); ) {
+            DebuggerTreeNodeImpl child = (DebuggerTreeNodeImpl)enumeration.nextElement();
+            nodeChanged(child);
+          }
+        }
+
+        private void nodeChanged(DebuggerTreeNodeImpl debuggerTreeNode) {
+          if(pathToThread.size() == 0) {
+            if(debuggerTreeNode.getDescriptor() instanceof ThreadDescriptorImpl && ((ThreadDescriptorImpl) debuggerTreeNode.getDescriptor()).getThreadReference() == thread) {
+              removeListener();
+              final TreePath treePath = new TreePath(debuggerTreeNode.getPath());
+              setSelectionPath(treePath);
+              if (expand && !isExpanded(treePath)) {
+                expandPath(treePath);
+              }
+            }
+          }
+          else {
+            if(debuggerTreeNode.getDescriptor() instanceof ThreadGroupDescriptorImpl && ((ThreadGroupDescriptorImpl) debuggerTreeNode.getDescriptor()).getThreadGroupReference() == pathToThread.get(0)) {
+              pathToThread.remove(0);
+              expandPath(new TreePath(debuggerTreeNode.getPath()));
+            }
+          }
+        }
+
+        private void removeListener() {
+          final TreeModelAdapter listener = this;
+          SwingUtilities.invokeLater(new Runnable() {
+            public void run() {
+              getModel().removeTreeModelListener(listener);
+            }
+          });
+        }
+
+        public void treeStructureChanged(TreeModelEvent event) {
+          if(event.getPath().length <= 1) {
+            removeListener();
+            return;
+          }
+          structureChanged((DebuggerTreeNodeImpl)event.getTreePath().getLastPathComponent());
+        }
+      }
+
+      MyTreeModelAdapter listener = new MyTreeModelAdapter();
+      listener.structureChanged((DebuggerTreeNodeImpl)getModel().getRoot());
+      getModel().addTreeModelListener(listener);
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/ThreadsPanel.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/ThreadsPanel.java
new file mode 100644
index 0000000..f6d2116
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/ThreadsPanel.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.impl;
+
+import com.intellij.debugger.actions.DebuggerAction;
+import com.intellij.debugger.actions.DebuggerActions;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.events.DebuggerCommandImpl;
+import com.intellij.debugger.impl.*;
+import com.intellij.debugger.jdi.StackFrameProxyImpl;
+import com.intellij.debugger.ui.impl.watch.DebuggerTree;
+import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
+import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl;
+import com.intellij.debugger.ui.impl.watch.StackFrameDescriptorImpl;
+import com.intellij.debugger.ui.tree.render.DescriptorLabelListener;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.actionSystem.ActionManager;
+import com.intellij.openapi.actionSystem.ActionPopupMenu;
+import com.intellij.openapi.actionSystem.DefaultActionGroup;
+import com.intellij.openapi.actionSystem.PlatformDataKeys;
+import com.intellij.openapi.application.ModalityState;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.ui.ScrollPaneFactory;
+import com.intellij.util.Alarm;
+import org.jetbrains.annotations.NonNls;
+
+import java.awt.*;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+
+public class ThreadsPanel extends DebuggerTreePanel{
+  @NonNls private static final String HELP_ID = "debugging.debugThreads";
+  private final Alarm myUpdateLabelsAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD);
+  private static final int LABELS_UPDATE_DELAY_MS = 200;
+
+  public ThreadsPanel(Project project, final DebuggerStateManager stateManager) {
+    super(project, stateManager);
+
+    final Disposable disposable = DebuggerAction.installEditAction(getThreadsTree(), DebuggerActions.EDIT_FRAME_SOURCE);
+    registerDisposable(disposable);
+
+    getThreadsTree().addKeyListener(new KeyAdapter() {
+      public void keyPressed(KeyEvent e) {
+        if (e.getKeyCode() == KeyEvent.VK_ENTER && getThreadsTree().getSelectionCount() == 1) {
+          DebuggerTreeNodeImpl node = (DebuggerTreeNodeImpl)getThreadsTree().getLastSelectedPathComponent();
+          if (node != null) {
+            NodeDescriptorImpl descriptor = node.getDescriptor();
+            if (descriptor instanceof StackFrameDescriptorImpl) {
+              selectFrame(node);
+            }
+          }
+        }
+      }
+    });
+    add(ScrollPaneFactory.createScrollPane(getThreadsTree()), BorderLayout.CENTER);
+    stateManager.addListener(new DebuggerContextListener() {
+      public void changeEvent(DebuggerContextImpl newContext, int event) {
+        if (DebuggerSession.EVENT_ATTACHED == event || DebuggerSession.EVENT_RESUME == event) {
+          startLabelsUpdate();
+        }
+        else if (DebuggerSession.EVENT_PAUSE == event || DebuggerSession.EVENT_DETACHED == event || DebuggerSession.EVENT_DISPOSE == event) {
+          myUpdateLabelsAlarm.cancelAllRequests();
+        }
+        if (DebuggerSession.EVENT_DETACHED == event || DebuggerSession.EVENT_DISPOSE == event) {
+          stateManager.removeListener(this);
+        }
+      }
+    });
+    startLabelsUpdate();
+  }
+
+  private void startLabelsUpdate() {
+    myUpdateLabelsAlarm.cancelAllRequests();
+    myUpdateLabelsAlarm.addRequest(new Runnable() {
+      public void run() {
+        boolean updateScheduled = false;
+        try {
+          if (isUpdateEnabled()) {
+            final ThreadsDebuggerTree tree = getThreadsTree();
+            final DebuggerTreeNodeImpl root = (DebuggerTreeNodeImpl)tree.getModel().getRoot();
+            if (root != null) {
+              final DebugProcessImpl process = getContext().getDebugProcess();
+              if (process != null) {
+                process.getManagerThread().invoke(new DebuggerCommandImpl() {
+                  protected void action() throws Exception {
+                    try {
+                      updateNodeLabels(root);
+                    }
+                    finally {
+                      reschedule();
+                    }
+                  }
+                  protected void commandCancelled() {
+                    reschedule();
+                  }
+                });
+                updateScheduled = true;
+              }
+            }
+          }
+        }
+        finally {
+          if (!updateScheduled) {
+            reschedule();
+          }
+        }
+      }
+
+      private void reschedule() {
+        final DebuggerSession session = getContext().getDebuggerSession();
+        if (session.isAttached() && !session.isPaused()) {
+          myUpdateLabelsAlarm.addRequest(this, LABELS_UPDATE_DELAY_MS, ModalityState.NON_MODAL);
+        }
+      }
+      
+    }, LABELS_UPDATE_DELAY_MS, ModalityState.NON_MODAL);
+  }
+
+  @Override
+  public void dispose() {
+    Disposer.dispose(myUpdateLabelsAlarm);
+    super.dispose();
+  }
+
+  private static void updateNodeLabels(DebuggerTreeNodeImpl from) {
+    final int childCount = from.getChildCount();
+    for (int idx = 0; idx < childCount; idx++) {
+      final DebuggerTreeNodeImpl child = (DebuggerTreeNodeImpl)from.getChildAt(idx);
+      child.getDescriptor().updateRepresentation(null, new DescriptorLabelListener() {
+        public void labelChanged() {
+          child.labelChanged();
+        }
+      });
+      updateNodeLabels(child);
+    }
+  }
+  
+  protected DebuggerTree createTreeView() {
+    return new ThreadsDebuggerTree(getProject());
+  }
+
+  protected ActionPopupMenu createPopupMenu() {
+    DefaultActionGroup group = (DefaultActionGroup)ActionManager.getInstance().getAction(DebuggerActions.THREADS_PANEL_POPUP);
+    return ActionManager.getInstance().createActionPopupMenu(DebuggerActions.THREADS_PANEL_POPUP, group);
+  }
+
+  public Object getData(String dataId) {
+    if (PlatformDataKeys.HELP_ID.is(dataId)) {
+      return HELP_ID;
+    }
+    return super.getData(dataId);
+  }
+
+  private void selectFrame(DebuggerTreeNodeImpl node) {
+    StackFrameProxyImpl frame = ((StackFrameDescriptorImpl)node.getDescriptor()).getFrameProxy();
+    DebuggerContextUtil.setStackFrame(getContextManager(), frame);
+  }
+
+  public ThreadsDebuggerTree getThreadsTree() {
+    return (ThreadsDebuggerTree) getTree();
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/TipManager.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/TipManager.java
new file mode 100644
index 0000000..5a8f0c1
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/TipManager.java
@@ -0,0 +1,374 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.impl;
+
+import com.intellij.debugger.settings.DebuggerSettings;
+import com.intellij.ide.FrameStateListener;
+import com.intellij.ide.FrameStateManager;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.CustomShortcutSet;
+import com.intellij.openapi.keymap.KeymapUtil;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.util.registry.Registry;
+import com.intellij.openapi.wm.IdeGlassPane;
+import com.intellij.openapi.wm.IdeGlassPaneUtil;
+import com.intellij.util.Alarm;
+import com.intellij.util.ui.UIUtil;
+import com.intellij.util.ui.update.Activatable;
+import com.intellij.util.ui.update.UiNotifyConnector;
+
+import javax.swing.*;
+import javax.swing.event.PopupMenuEvent;
+import javax.swing.event.PopupMenuListener;
+import java.awt.*;
+import java.awt.event.*;
+
+/**
+ * @author lex
+ */
+public class TipManager implements Disposable, PopupMenuListener {
+
+  private volatile boolean myIsDisposed = false;
+  private boolean myPopupShown;
+  private MyAwtPreprocessor myHideCanceller;
+
+  private MouseEvent myLastMouseEvent;
+
+  public interface TipFactory {
+    JComponent createToolTip (MouseEvent e);
+    MouseEvent createTooltipEvent(MouseEvent candidateEvent);
+    boolean isFocusOwner();
+  }
+
+
+  private boolean isOverTip(MouseEvent e) {
+    if (myCurrentTooltip != null) {
+      if(!myCurrentTooltip.isShowing()) {
+        hideTooltip(true);
+        return false;
+      }
+      final Component eventOriginator = e.getComponent();
+      if (eventOriginator == null) {
+        return false;
+      }
+      final Point point = e.getPoint();
+      SwingUtilities.convertPointToScreen(point, eventOriginator);
+
+      final Rectangle bounds = myCurrentTooltip.getBounds();
+      final Point tooltipLocationOnScreen = myCurrentTooltip.getLocationOnScreen();
+      bounds.setLocation(tooltipLocationOnScreen.x, tooltipLocationOnScreen.y);
+
+      return bounds.contains(point);
+    }
+    return false;
+  }
+
+  boolean myInsideComponent;
+
+  private class MyMouseListener extends MouseAdapter {
+    @Override
+    public void mouseExited(final MouseEvent e) {
+      myInsideComponent = false;
+    }
+
+    @Override
+    public void mousePressed(final MouseEvent e) {
+      if (myInsideComponent) {
+        hideTooltip(true);
+      }
+    }
+
+    @Override
+    public void mouseEntered(final MouseEvent e) {
+      myInsideComponent = true;
+    }
+  }
+
+  private class MyFrameStateListener implements FrameStateListener {
+    @Override
+    public void onFrameDeactivated() {
+      hideTooltip(true);
+    }
+
+    @Override
+    public void onFrameActivated() {
+      //Do nothing
+    }
+  }
+
+  public JPopupMenu registerPopup(JPopupMenu menu) {
+    menu.addPopupMenuListener(this);
+    return menu;
+  }
+
+  public void popupMenuWillBecomeVisible(final PopupMenuEvent e) {
+    myPopupShown = true;
+  }
+
+  public void popupMenuWillBecomeInvisible(final PopupMenuEvent e) {
+    onPopupClosed(e);
+  }
+
+  public void popupMenuCanceled(final PopupMenuEvent e) {
+    onPopupClosed(e);
+  }
+
+  private void onPopupClosed(final PopupMenuEvent e) {
+    myPopupShown = false;
+    if (e.getSource() instanceof JPopupMenu) {
+      ((JPopupMenu)e.getSource()).removePopupMenuListener(this);
+    }
+  }
+
+  private class MyMouseMotionListener extends MouseMotionAdapter {
+    @Override
+    public void mouseMoved(final MouseEvent e) {
+      myLastMouseEvent = e;
+
+      if (!myComponent.isShowing()) return;
+
+      myInsideComponent = true;
+
+      if (myCurrentTooltip == null) {
+        if (isInsideComponent(e)) {
+          tryTooltip(e, true);
+        }
+      } else {
+        if (!isOverTip(e)) {
+          tryTooltip(e, true);
+        }
+      }
+    }
+
+  }
+
+  private boolean isInsideComponent(final MouseEvent e) {
+    final Rectangle compBounds = myComponent.getBounds();
+    final Point compPoint = SwingUtilities.convertPoint(e.getComponent(), e.getPoint(), myComponent);
+
+    return compBounds.contains(compPoint);
+  }
+
+
+  private void tryTooltip(final InputEvent e, final boolean auto) {
+    myShowAlarm.cancelAllRequests();
+    myHideAlarm.cancelAllRequests();
+    myShowAlarm.addRequest(new Runnable() {
+      public void run() {
+        if (!myIsDisposed && !myPopupShown) {
+          showTooltip(e, auto);
+        }
+      }
+    }, auto ? DebuggerSettings.getInstance().VALUE_LOOKUP_DELAY : 10);
+  }
+
+  private void showTooltip(InputEvent e, boolean auto) {
+    if (auto && !Registry.is("debugger.valueTooltipAutoShow")) return;
+
+    MouseEvent sourceEvent = null;
+    JComponent newTip = null;
+
+    if (e instanceof MouseEvent) {
+      sourceEvent = (MouseEvent)e;
+    } else if (e instanceof KeyEvent) {
+      sourceEvent = myTipFactory.createTooltipEvent(myLastMouseEvent);
+    }
+
+
+    MouseEvent convertedEvent = null;
+    if (sourceEvent != null) {
+      convertedEvent = SwingUtilities.convertMouseEvent(sourceEvent.getComponent(), sourceEvent, myComponent);
+      newTip = myTipFactory.createToolTip(convertedEvent);
+    }
+
+    if (newTip == null || (auto && !myTipFactory.isFocusOwner())) {
+      hideTooltip(false);
+      return;
+    }
+
+    if(newTip == myCurrentTooltip) {
+      if (!auto) {
+        hideTooltip(true);
+        return;
+      }
+      return;
+    }
+
+    hideTooltip(true);
+
+    if(myComponent.isShowing()) {
+      PopupFactory popupFactory = PopupFactory.getSharedInstance();
+      final Point location = convertedEvent.getPoint();
+      final Component sourceComponent = convertedEvent.getComponent();
+      if (sourceComponent != null) {
+        SwingUtilities.convertPointToScreen(location, sourceComponent);
+      }
+
+      myTipPopup = popupFactory.getPopup(myComponent, newTip, location.x, location.y);
+      myInsideComponent = false;
+      myTipPopup.show();
+      myCurrentTooltip = newTip;
+    }
+  }
+
+  public void hideTooltip() {
+    hideTooltip(true);
+  }
+  
+  public void hideTooltip(boolean now) {
+    if (myTipPopup == null) return;
+
+    if (now) {
+      myHideAlarm.cancelAllRequests();
+      myTipPopup.hide();
+      myTipPopup = null;
+      myCurrentTooltip = null;
+    } else {
+      myHideAlarm.addRequest(new Runnable() {
+        public void run() {
+          if (myInsideComponent) {
+            hideTooltip(true);
+          }
+        }
+      }, 100);
+    }
+  }
+
+  private JComponent myCurrentTooltip;
+  private Popup myTipPopup;
+  private final TipFactory myTipFactory;
+  private final JComponent myComponent;
+  private MouseListener myMouseListener = new MyMouseListener();
+  private MouseMotionListener myMouseMotionListener = new MyMouseMotionListener();
+  private FrameStateListener myFrameStateListener = new MyFrameStateListener();
+
+  private final Alarm myShowAlarm = new Alarm();
+  private final Alarm myHideAlarm = new Alarm();
+
+
+  private IdeGlassPane myGP;
+
+  public TipManager(final JComponent component, TipFactory factory) {
+    myTipFactory = factory;
+    myComponent = component;
+
+    new UiNotifyConnector.Once(component, new Activatable() {
+      public void showNotify() {
+        installListeners();
+      }
+
+      public void hideNotify() {
+      }
+    });
+
+    final HideTooltipAction hide = new HideTooltipAction();
+    hide.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0)), myComponent);
+    Disposer.register(this, new Disposable() {
+      public void dispose() {
+        hide.unregisterCustomShortcutSet(myComponent);
+      }
+    });
+  }
+
+
+  private class HideTooltipAction extends AnAction {
+    public void actionPerformed(AnActionEvent e) {
+      hideTooltip(true);
+    }
+
+    @Override
+    public void update(AnActionEvent e) {
+      e.getPresentation().setEnabled(myTipPopup != null);
+    }
+  }
+
+  private void installListeners() {
+    if (myIsDisposed) return;
+
+    myGP = IdeGlassPaneUtil.find(myComponent);
+    assert myGP != null;
+
+    myGP.addMousePreprocessor(myMouseListener, this);
+    myGP.addMouseMotionPreprocessor(myMouseMotionListener, this);
+
+    myHideCanceller = new MyAwtPreprocessor();
+    Toolkit.getDefaultToolkit().addAWTEventListener(myHideCanceller, AWTEvent.MOUSE_MOTION_EVENT_MASK | AWTEvent.KEY_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK);
+    FrameStateManager.getInstance().addListener(myFrameStateListener);
+  }
+
+  public void dispose() {
+    Disposer.dispose(this);
+
+    hideTooltip(true);
+
+    Toolkit.getDefaultToolkit().removeAWTEventListener(myHideCanceller);
+
+    myIsDisposed = true;
+    myShowAlarm.cancelAllRequests();
+    myMouseListener = null;
+    myMouseMotionListener = null;
+    FrameStateManager.getInstance().removeListener(myFrameStateListener);
+    myFrameStateListener = null;
+  }
+
+  private class MyAwtPreprocessor implements AWTEventListener {
+
+    public void eventDispatched(AWTEvent event) {
+      if (event.getID() == MouseEvent.MOUSE_MOVED) {
+        preventFromHideIfInsideTooltip(event);
+      } else if (event.getID() == MouseEvent.MOUSE_PRESSED || event.getID() == MouseEvent.MOUSE_RELEASED) {
+        hideTooltipIfCloseClick((MouseEvent)event);
+      } else if (event instanceof KeyEvent) {
+        tryToShowTooltipIfRequested((KeyEvent)event);
+      }
+    }
+
+    private void hideTooltipIfCloseClick(MouseEvent me) {
+      if (myCurrentTooltip == null) return;
+
+      if (isInsideTooltip(me) && UIUtil.isCloseClick(me)) {
+        hideTooltip(true);
+      }
+    }
+
+    private void tryToShowTooltipIfRequested(KeyEvent event) {
+      if (KeymapUtil.isTooltipRequest(event)) {
+        tryTooltip(event, false);
+      } else {
+        if (event.getID() == KeyEvent.KEY_PRESSED) {
+          myLastMouseEvent = null;
+        }
+      }
+    }
+
+    private void preventFromHideIfInsideTooltip(AWTEvent event) {
+      if (myCurrentTooltip == null) return;
+
+      if (event.getID() == MouseEvent.MOUSE_MOVED) {
+        final MouseEvent me = (MouseEvent)event;
+        if (isInsideTooltip(me)) {
+          myHideAlarm.cancelAllRequests();
+        }
+      }
+    }
+
+    private boolean isInsideTooltip(MouseEvent me) {
+      return myCurrentTooltip == me.getComponent() || SwingUtilities.isDescendingFrom(me.getComponent(), myCurrentTooltip);
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/UpdatableDebuggerView.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/UpdatableDebuggerView.java
new file mode 100644
index 0000000..97a5fd8
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/UpdatableDebuggerView.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.impl;
+
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerContextListener;
+import com.intellij.debugger.impl.DebuggerStateManager;
+import com.intellij.debugger.ui.DebuggerView;
+import com.intellij.openapi.CompositeDisposable;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.actionSystem.ActionManager;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.ShortcutSet;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Disposer;
+
+import javax.swing.*;
+import java.awt.*;
+
+public abstract class UpdatableDebuggerView extends JPanel implements DebuggerView {
+  private final Project myProject;
+  private final DebuggerStateManager myStateManager;
+  private volatile boolean myRefreshNeeded = true;
+  private final CompositeDisposable myDisposables = new CompositeDisposable();
+  private volatile boolean myUpdateEnabled;
+
+  protected UpdatableDebuggerView(final Project project, final DebuggerStateManager stateManager) {
+    setLayout(new BorderLayout());
+    myProject = project;
+    myStateManager = stateManager;
+
+    final DebuggerContextListener contextListener = new DebuggerContextListener() {
+      public void changeEvent(DebuggerContextImpl newContext, int event) {
+        UpdatableDebuggerView.this.changeEvent(newContext, event);
+      }
+    };
+    myStateManager.addListener(contextListener);
+
+    registerDisposable(new Disposable() {
+      public void dispose() {
+        myStateManager.removeListener(contextListener);
+      }
+    });
+
+  }
+
+  protected void changeEvent(final DebuggerContextImpl newContext, final int event) {
+    if (newContext.getDebuggerSession() != null) {
+      rebuildIfVisible(event);
+    }
+  }
+
+  protected final boolean isUpdateEnabled() {
+    return myUpdateEnabled || isShowing();
+  }
+
+  public final void setUpdateEnabled(final boolean enabled) {
+    myUpdateEnabled = enabled;
+  }
+
+  public final boolean isRefreshNeeded() {
+    return myRefreshNeeded;
+  }
+
+  public final void rebuildIfVisible(final int event) {
+    if(isUpdateEnabled()) {
+      myRefreshNeeded = false;
+      rebuild(event);
+    }
+    else {
+      myRefreshNeeded = true;
+    }
+  }
+
+  protected abstract void rebuild(int event);
+
+  protected final void registerDisposable(Disposable disposable) {
+    myDisposables.add(disposable);
+  }
+
+  public DebuggerContextImpl getContext() {
+    return myStateManager.getContext();
+  }
+
+  protected final Project getProject() {
+    return myProject;
+  }
+
+  public DebuggerStateManager getContextManager() {
+    return myStateManager;
+  }
+
+  public void dispose() {
+    Disposer.dispose(myDisposables);
+  }
+
+  protected void overrideShortcut(final JComponent forComponent, final String actionId, final ShortcutSet shortcutSet) {
+    final AnAction action = ActionManager.getInstance().getAction(actionId);
+    action.registerCustomShortcutSet(shortcutSet, forComponent);
+    registerDisposable(new Disposable() {
+      public void dispose() {
+        action.unregisterCustomShortcutSet(forComponent);
+      }
+    });
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/ValueNodeDnD.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/ValueNodeDnD.java
new file mode 100644
index 0000000..cb006ae
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/ValueNodeDnD.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.impl;
+
+import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
+import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl;
+import com.intellij.ide.dnd.DnDAction;
+import com.intellij.ide.dnd.DnDDragStartBean;
+import com.intellij.ide.dnd.DnDManager;
+import com.intellij.ide.dnd.DnDSource;
+import com.intellij.ide.dnd.aware.DnDAwareTree;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.util.Pair;
+import com.intellij.ui.treeStructure.Tree;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.tree.TreePath;
+import java.awt.*;
+
+public class ValueNodeDnD {
+  private final DnDAwareTree myTree;
+
+  public ValueNodeDnD(DnDAwareTree tree, Disposable parent) {
+    myTree = tree;
+
+    DnDManager.getInstance().registerSource(new DnDSource() {
+      public boolean canStartDragging(final DnDAction action, final Point dragOrigin) {
+        return getNodesToDrag().length > 0;
+      }
+
+      public DnDDragStartBean startDragging(final DnDAction action, final Point dragOrigin) {
+        DebuggerTreeNodeImpl[] nodes = getNodesToDrag();
+        return new DnDDragStartBean(nodes);
+      }
+
+      @Nullable
+      public Pair<Image, Point> createDraggedImage(final DnDAction action, final Point dragOrigin) {
+        DebuggerTreeNodeImpl[] nodes = getNodesToDrag();
+
+        Pair<Image, Point> image;
+        if (nodes.length == 1) {
+          image = DnDAwareTree.getDragImage(myTree, new TreePath(nodes[0].getPath()), dragOrigin);
+        } else {
+          image = DnDAwareTree.getDragImage(myTree, nodes.length + " elements", dragOrigin);
+        }
+
+        return image;
+      }
+
+      public void dragDropEnd() {
+      }
+
+      public void dropActionChanged(final int gestureModifiers) {
+      }
+    }, tree);
+  }
+
+  private DebuggerTreeNodeImpl[] getNodesToDrag() {
+    return myTree.getSelectedNodes(DebuggerTreeNodeImpl.class, new Tree.NodeFilter<DebuggerTreeNodeImpl>() {
+      public boolean accept(final DebuggerTreeNodeImpl node) {
+        return node.getDescriptor() instanceof ValueDescriptorImpl;
+      }
+    });
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/VariablesPanel.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/VariablesPanel.java
new file mode 100644
index 0000000..af48223
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/VariablesPanel.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.impl;
+
+import com.intellij.debugger.actions.DebuggerAction;
+import com.intellij.debugger.actions.DebuggerActions;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.debugger.impl.DebuggerStateManager;
+import com.intellij.debugger.ui.impl.watch.DebuggerTree;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.project.Project;
+import com.intellij.ui.ScrollPaneFactory;
+import org.jetbrains.annotations.NonNls;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.KeyEvent;
+
+public class VariablesPanel extends DebuggerTreePanel implements DataProvider{
+
+  @NonNls private static final String HELP_ID = "debugging.debugFrame";
+
+  public VariablesPanel(Project project, DebuggerStateManager stateManager, Disposable parent) {
+    super(project, stateManager);
+    setBorder(null);
+
+
+    final FrameVariablesTree frameTree = getFrameTree();
+
+    add(ScrollPaneFactory.createScrollPane(frameTree), BorderLayout.CENTER);
+    registerDisposable(DebuggerAction.installEditAction(frameTree, DebuggerActions.EDIT_NODE_SOURCE));
+
+    overrideShortcut(frameTree, DebuggerActions.COPY_VALUE, CommonShortcuts.getCopy());
+    overrideShortcut(frameTree, DebuggerActions.SET_VALUE, new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0)));
+
+    new ValueNodeDnD(myTree, parent);
+  }
+
+  protected DebuggerTree createTreeView() {
+    return new FrameVariablesTree(getProject());
+  }
+
+  protected void changeEvent(DebuggerContextImpl newContext, int event) {
+    if (event != DebuggerSession.EVENT_THREADS_REFRESH) {
+      super.changeEvent(newContext, event);
+    }
+  }
+
+  protected ActionPopupMenu createPopupMenu() {
+    ActionGroup group = (ActionGroup)ActionManager.getInstance().getAction(DebuggerActions.FRAME_PANEL_POPUP);
+    return ActionManager.getInstance().createActionPopupMenu(DebuggerActions.FRAME_PANEL_POPUP, group);
+  }
+
+  public Object getData(String dataId) {
+    if (PlatformDataKeys.HELP_ID.is(dataId)) {
+      return HELP_ID;
+    }
+    return super.getData(dataId);
+  }
+
+
+  public FrameVariablesTree getFrameTree() {
+    return (FrameVariablesTree) getTree();
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/WatchDebuggerTree.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/WatchDebuggerTree.java
new file mode 100644
index 0000000..8282adf
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/WatchDebuggerTree.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.impl;
+
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.ui.impl.watch.DebuggerTree;
+import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
+import com.intellij.debugger.ui.impl.watch.WatchItemDescriptor;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.xdebugger.XDebuggerBundle;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.tree.TreePath;
+import java.util.Enumeration;
+
+public class WatchDebuggerTree extends DebuggerTree {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.impl.WatchDebuggerTree");
+
+  public WatchDebuggerTree(Project project) {
+    super(project);
+    getEmptyText().setText(XDebuggerBundle.message("debugger.no.watches"));
+  }
+
+  public DebuggerTreeNodeImpl[] getWatches() {
+    DebuggerTreeNodeImpl root = (DebuggerTreeNodeImpl)getModel().getRoot();
+    DebuggerTreeNodeImpl[] watches = new DebuggerTreeNodeImpl[root.getChildCount()];
+
+    final Enumeration e = root.children();
+    int i = 0;
+    while(e.hasMoreElements()) {
+      watches[i++] = (DebuggerTreeNodeImpl)e.nextElement();
+    }
+
+    return watches;
+  }
+
+  public int getWatchCount() {
+    DebuggerTreeNodeImpl root = (DebuggerTreeNodeImpl) getModel().getRoot();
+    return root != null ? root.getChildCount() : 0;
+  }
+
+  public DebuggerTreeNodeImpl addWatch(WatchItemDescriptor descriptor) {
+    ApplicationManager.getApplication().assertIsDispatchThread();
+    final DebuggerTreeNodeImpl root = (DebuggerTreeNodeImpl) getModel().getRoot();
+    WatchItemDescriptor watchDescriptor = new WatchItemDescriptor(getProject(), descriptor.getEvaluationText());
+    watchDescriptor.displayAs(descriptor);
+
+    final DebuggerTreeNodeImpl node = DebuggerTreeNodeImpl.createNodeNoUpdate(this, watchDescriptor);
+    root.add(node);
+
+    treeChanged();
+    getSelectionModel().setSelectionPath(new TreePath(node.getPath()));
+
+    //node.calcValue();
+
+    return node;
+  }
+
+  public DebuggerTreeNodeImpl addWatch(TextWithImports text, @Nullable String customName) {
+    ApplicationManager.getApplication().assertIsDispatchThread();
+    final DebuggerTreeNodeImpl root = (DebuggerTreeNodeImpl) getModel().getRoot();
+    final WatchItemDescriptor descriptor = new WatchItemDescriptor(getProject(), text);
+    descriptor.setCustomName(customName);
+    DebuggerTreeNodeImpl node = DebuggerTreeNodeImpl.createNodeNoUpdate(this, descriptor);
+    root.add(node);
+
+    treeChanged();
+    final TreePath path = new TreePath(node.getPath());
+    getSelectionModel().setSelectionPath(path);
+    scrollPathToVisible(path);
+    return node;
+  }
+
+  public void removeWatch(DebuggerTreeNodeImpl node) {
+    ApplicationManager.getApplication().assertIsDispatchThread();
+    LOG.assertTrue(node.getDescriptor() instanceof WatchItemDescriptor);
+
+    DebuggerTreeNodeImpl root          = (DebuggerTreeNodeImpl) getModel().getRoot();
+    DebuggerTreeNodeImpl nodeToSelect  = (DebuggerTreeNodeImpl) node.getNextSibling();
+
+    getMutableModel().removeNodeFromParent(node);
+    treeChanged();
+
+    if(nodeToSelect == null && root.getChildCount() > 0) {
+      nodeToSelect = (DebuggerTreeNodeImpl) root.getChildAt(root.getChildCount() - 1);
+    }
+
+    if(nodeToSelect != null) {
+      setSelectionPath(new TreePath(nodeToSelect.getPath()));
+    }
+  }
+
+  protected void build(DebuggerContextImpl context) {
+    for (DebuggerTreeNodeImpl node : getWatches()) {
+      node.calcValue();
+    }
+  }
+
+  public static void setWatchNodeText(final DebuggerTreeNodeImpl node, TextWithImports text) {
+    ((WatchItemDescriptor)node.getDescriptor()).setEvaluationText(text);
+    node.calcValue();
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/WatchPanel.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/WatchPanel.java
new file mode 100644
index 0000000..8d9cefc
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/WatchPanel.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class WatchPanel
+ * @author Jeka
+ */
+package com.intellij.debugger.ui.impl;
+
+import com.intellij.debugger.actions.DebuggerAction;
+import com.intellij.debugger.actions.DebuggerActions;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.debugger.impl.DebuggerStateManager;
+import com.intellij.debugger.ui.impl.watch.DebuggerTree;
+import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
+import com.intellij.debugger.ui.impl.watch.WatchItemDescriptor;
+import com.intellij.openapi.actionSystem.ActionPopupMenu;
+import com.intellij.openapi.actionSystem.CommonShortcuts;
+import com.intellij.openapi.actionSystem.PlatformDataKeys;
+import com.intellij.openapi.project.Project;
+import com.intellij.ui.ScrollPaneFactory;
+import org.jetbrains.annotations.NonNls;
+
+import javax.swing.*;
+import java.awt.*;
+import java.util.Enumeration;
+
+public abstract class WatchPanel extends DebuggerTreePanel {
+  @NonNls private static final String HELP_ID = "debugging.debugWatches";
+
+  public WatchPanel(Project project, DebuggerStateManager stateManager) {
+    super(project, stateManager);
+    add(createTreePanel(getWatchTree()), BorderLayout.CENTER);
+    registerDisposable(DebuggerAction.installEditAction(getWatchTree(), DebuggerActions.EDIT_NODE_SOURCE));
+    overrideShortcut(getWatchTree(), DebuggerActions.COPY_VALUE, CommonShortcuts.getCopy());
+  }
+
+  protected JComponent createTreePanel(final WatchDebuggerTree tree) {
+    return ScrollPaneFactory.createScrollPane(tree);
+  }
+
+  protected DebuggerTree createTreeView() {
+    return new WatchDebuggerTree(getProject());
+  }
+
+  protected void changeEvent(DebuggerContextImpl newContext, int event) {
+    if (event == DebuggerSession.EVENT_THREADS_REFRESH) {
+      return;
+    }
+    if(event == DebuggerSession.EVENT_ATTACHED) {
+      DebuggerTreeNodeImpl root = (DebuggerTreeNodeImpl) getWatchTree().getModel().getRoot();
+      if(root != null) {
+        for(Enumeration e = root.rawChildren(); e.hasMoreElements();) {
+          DebuggerTreeNodeImpl child = (DebuggerTreeNodeImpl) e.nextElement();
+          ((WatchItemDescriptor) child.getDescriptor()).setNew();
+        }
+      }
+    }
+
+    rebuildIfVisible(event);
+  }
+
+  protected ActionPopupMenu createPopupMenu() {
+    return null;
+  }
+
+  public Object getData(String dataId) {
+    if (PlatformDataKeys.HELP_ID.is(dataId)) {
+      return HELP_ID;
+    }
+    return super.getData(dataId);
+  }
+
+  public WatchDebuggerTree getWatchTree() {
+    return (WatchDebuggerTree) getTree();
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/nodes/ArrayIndexHelper.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/nodes/ArrayIndexHelper.java
new file mode 100644
index 0000000..f828a0e
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/nodes/ArrayIndexHelper.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class ArrayIndexHelper
+ * @author Jeka
+ */
+package com.intellij.debugger.ui.impl.nodes;
+
+import com.intellij.debugger.ui.tree.render.ArrayRenderer;
+import com.intellij.debugger.ui.tree.render.ArrayRenderer;
+import com.intellij.openapi.diagnostic.Logger;
+import com.sun.jdi.ArrayReference;
+
+public class ArrayIndexHelper {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.impl.nodes.ArrayIndexHelper");
+  private final ArrayReference myArray;
+  private final ArrayRenderer myRenderer;
+
+  public ArrayIndexHelper(ArrayReference array, ArrayRenderer renderer) {
+    myRenderer = renderer;
+    myArray = array;
+  }
+
+  /**
+   * @return normalized start index or -1 if this is not an array or array's length == 0
+   */
+  public int getStartIndex() {
+    if (myArray.length() == 0) return -1;
+    return myRenderer.START_INDEX;
+  }
+
+  /**
+   * @return normalized end index or -1 if this is not an array or array's length == 0
+   */
+
+  public int getEndIndex() {
+    return Math.min(myArray.length() - 1, myRenderer.END_INDEX);
+  }
+
+  public ArrayRenderer newRenderer(int startIdx, int endIdx) {
+    ArrayRenderer result = myRenderer.clone();
+    result.START_INDEX = startIdx < myArray.length() ? startIdx : 0;
+    result.END_INDEX   = startIdx <= endIdx ? endIdx : startIdx;
+    return result;
+  }
+}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/nodes/NodeComparator.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/nodes/NodeComparator.java
new file mode 100644
index 0000000..4c2a694
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/nodes/NodeComparator.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class NodeComparator
+ * @author Jeka
+ */
+package com.intellij.debugger.ui.impl.nodes;
+
+import com.intellij.debugger.ui.tree.DebuggerTreeNode;
+
+import java.util.Comparator;
+
+/**
+ * Compares given DebuggerTreeTest by name
+ */
+public class NodeComparator implements Comparator<DebuggerTreeNode> {
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  public int compare(final DebuggerTreeNode node1, final DebuggerTreeNode node2) {
+    final String name1 = node1.getDescriptor().getName();
+    final String name2 = node2.getDescriptor().getName();
+    final boolean invalid1 = (name1 == null || (name1.length() > 0 && Character.isDigit(name1.charAt(0))));
+    final boolean invalid2 = (name2 == null || (name2.length() > 0 && Character.isDigit(name2.charAt(0))));
+    if (invalid1) {
+      return invalid2? 0 : 1;
+    }
+    else if (invalid2) {
+      return -1;
+    }
+    if ("this".equals(name1) || "static".equals(name1)) {
+      return -1;
+    }
+    if ("this".equals(name2) || "static".equals(name2)) {
+      return 1;
+    }
+    return name1.compareToIgnoreCase(name2);
+  }
+}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/tree/TreeBuilder.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/tree/TreeBuilder.java
new file mode 100644
index 0000000..9686603
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/tree/TreeBuilder.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.impl.tree;
+
+import com.intellij.util.EventDispatcher;
+
+import javax.swing.event.TreeModelEvent;
+import javax.swing.event.TreeModelListener;
+import javax.swing.tree.TreeModel;
+import javax.swing.tree.TreeNode;
+import javax.swing.tree.TreePath;
+
+/**
+ * User: lex
+ * Date: Sep 10, 2003
+ * Time: 6:56:51 PM
+ */
+public abstract class TreeBuilder implements TreeModel {
+  private final Object userObject;
+  private TreeBuilderNode myRoot;
+  private final EventDispatcher<TreeModelListener> myDispatcher = EventDispatcher.create(TreeModelListener.class);
+
+  protected TreeBuilder(Object userObject) {
+    this.userObject = userObject;
+  }
+
+  public Object getUserObject() {
+    return userObject;
+  }
+
+  public abstract void buildChildren(TreeBuilderNode node);
+  public abstract boolean isExpandable (TreeBuilderNode node);
+
+  public void setRoot(TreeBuilderNode root) {
+    myRoot = root;
+  }
+
+  public Object getRoot() {
+    return myRoot;
+  }
+
+  public int getChildCount(Object parent) {
+    return ((TreeBuilderNode) parent).getChildCount();
+  }
+
+  public boolean isLeaf(Object node) {
+    return ((TreeBuilderNode) node).isLeaf();
+  }
+
+  public void addTreeModelListener(TreeModelListener l) {
+    myDispatcher.addListener(l);
+  }
+
+  public void removeTreeModelListener(TreeModelListener l) {
+    myDispatcher.removeListener(l);
+  }
+
+  public Object getChild(Object parent, int index) {
+    return ((TreeBuilderNode) parent).getChildAt(index);
+  }
+
+  public int getIndexOfChild(Object parent, Object child) {
+    return ((TreeBuilderNode) parent).getIndex((TreeNode) child);
+  }
+
+  public void valueForPathChanged(TreePath path, Object newValue) {
+    TreeBuilderNode  aNode = (TreeBuilderNode) path.getLastPathComponent();
+
+    aNode.setUserObject(newValue);
+    nodeChanged(aNode);
+  }
+
+  public void nodeChanged(TreeNode node) {
+    TreeModelEvent event = null;
+    TreeNode parent = node.getParent();
+    if (parent != null) {
+      int anIndex = parent.getIndex(node);
+      event = new TreeModelEvent(this, getPathToRoot(parent, 0), new int[] {anIndex}, new Object[] {node});
+    } else if (node == getRoot()) {
+      event = new TreeModelEvent(this, getPathToRoot(node, 0), null, null);
+    }
+    if (event != null) {
+      myDispatcher.getMulticaster().treeNodesChanged(event);
+    }
+  }
+
+  public void nodeStructureChanged(TreeNode node) {
+    TreeModelEvent event = new TreeModelEvent(this, getPathToRoot(node, 0), null, null);
+    myDispatcher.getMulticaster().treeStructureChanged(event);
+  }
+
+  protected TreeNode[] getPathToRoot(TreeNode aNode, int depth) {
+      TreeNode[]              retNodes;
+      if(aNode == null) {
+          if(depth == 0)
+              return null;
+          else
+              retNodes = new TreeNode[depth];
+      }
+      else {
+          depth++;
+          if(aNode == myRoot)
+              retNodes = new TreeNode[depth];
+          else
+              retNodes = getPathToRoot(aNode.getParent(), depth);
+          retNodes[retNodes.length - depth] = aNode;
+      }
+      return retNodes;
+  }
+
+  public void removeNodeFromParent(TreeBuilderNode node) {
+    final TreeBuilderNode parent = (TreeBuilderNode)node.getParent();
+    if (parent != null) {
+      parent.remove(node);
+    }
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/tree/TreeBuilderNode.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/tree/TreeBuilderNode.java
new file mode 100644
index 0000000..f67946f
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/tree/TreeBuilderNode.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.impl.tree;
+
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.TreeNode;
+import java.util.Enumeration;
+
+/**
+ * User: lex
+ * Date: Sep 10, 2003
+ * Time: 7:01:02 PM
+ */
+public abstract class TreeBuilderNode extends DefaultMutableTreeNode{
+  private boolean  myChildrenBuilt = false;
+
+  public TreeBuilderNode(Object userObject) {
+    super(userObject);
+  }
+
+  abstract protected TreeBuilder getTreeBuilder();
+
+  private void checkChildren() {
+    synchronized (this) {
+      if (myChildrenBuilt) {
+        return;
+      }
+      myChildrenBuilt = true;
+    }
+    final TreeBuilder treeBuilder = getTreeBuilder();
+    if(treeBuilder.isExpandable(this)) {
+      treeBuilder.buildChildren(this);
+    }
+  }
+
+  public void clear() {
+    synchronized (this) {
+      myChildrenBuilt = false;
+    }
+  }
+
+  //TreeNode interface
+  public int getChildCount() {
+    checkChildren();
+    return super.getChildCount();
+  }
+
+  public boolean getAllowsChildren() {
+    checkChildren();
+    return super.getAllowsChildren();
+  }
+
+  public boolean isLeaf() {
+    return !getTreeBuilder().isExpandable(this);
+  }
+
+  public Enumeration children() {
+    checkChildren();
+    return super.children();
+  }
+
+  public Enumeration rawChildren() {
+    return super.children();
+  }
+
+  public TreeNode getChildAt(int childIndex) {
+    checkChildren();
+    return super.getChildAt(childIndex);
+  }
+
+  public int getIndex(TreeNode node) {
+    checkChildren();
+    return super.getIndex(node);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ArgumentValueDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ArgumentValueDescriptorImpl.java
new file mode 100644
index 0000000..3b87a5f
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ArgumentValueDescriptorImpl.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.impl.watch;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerContext;
+import com.intellij.debugger.SourcePosition;
+import com.intellij.debugger.engine.ContextUtil;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.impl.PositionUtil;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.*;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.util.IncorrectOperationException;
+import com.sun.jdi.PrimitiveValue;
+import com.sun.jdi.Value;
+
+public class ArgumentValueDescriptorImpl extends ValueDescriptorImpl{
+  private final int myIndex;
+  private final Value myValue;
+  private String myName;
+  private boolean myParameterNameCalcutated;
+
+  public ArgumentValueDescriptorImpl(Project project, int index, Value value) {
+    super(project);
+    myIndex = index;
+    myValue = value;
+    myName = "arg" + String.valueOf(index);
+    setLvalue(true);
+  }
+
+  public boolean isPrimitive() {
+    return myValue instanceof PrimitiveValue;
+  }
+
+  public Value calcValue(final EvaluationContextImpl evaluationContext) throws EvaluateException {
+    ApplicationManager.getApplication().runReadAction(new Runnable() {
+      public void run() {
+        final SourcePosition position = ContextUtil.getSourcePosition(evaluationContext);
+        if (position != null) {
+          final PsiMethod method = PsiTreeUtil.getParentOfType(position.getElementAt(), PsiMethod.class);
+          if (method != null) {
+            final PsiParameterList params = method.getParameterList();
+            if (myIndex < params.getParametersCount()) {
+              final PsiParameter param = params.getParameters()[myIndex];
+              myName = param.getName();
+              myParameterNameCalcutated = true;
+            }
+          }
+        }
+      }
+    });
+    return myValue;
+  }
+
+  public String getName() {
+    return myName;
+  }
+
+  public String calcValueName() {
+    return getName();
+  }
+
+  public PsiExpression getDescriptorEvaluation(DebuggerContext context) throws EvaluateException {
+    if (!myParameterNameCalcutated) {
+      return null;
+    }
+    PsiElementFactory elementFactory = JavaPsiFacade.getInstance(context.getProject()).getElementFactory();
+    try {
+      return elementFactory.createExpressionFromText(getName(), PositionUtil.getContextElement(context));
+    }
+    catch (IncorrectOperationException e) {
+      throw new EvaluateException(DebuggerBundle.message("error.invalid.local.variable.name", getName()), e);
+    }
+  }
+}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ArrayElementDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ArrayElementDescriptorImpl.java
new file mode 100644
index 0000000..93982cc
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ArrayElementDescriptorImpl.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.impl.watch;
+
+import com.intellij.debugger.DebuggerContext;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.ui.tree.ArrayElementDescriptor;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.JavaPsiFacade;
+import com.intellij.psi.PsiElementFactory;
+import com.intellij.psi.PsiExpression;
+import com.intellij.util.IncorrectOperationException;
+import com.sun.jdi.ArrayReference;
+import com.sun.jdi.ObjectCollectedException;
+import com.sun.jdi.Value;
+
+public class ArrayElementDescriptorImpl extends ValueDescriptorImpl implements ArrayElementDescriptor{
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.impl.watch.ArrayElementDescriptorImpl");
+
+  private final int myIndex;
+  private final ArrayReference myArray;
+
+  public ArrayElementDescriptorImpl(Project project, ArrayReference array, int index) {
+    super(project);
+    myArray = array;
+    myIndex = index;
+    setLvalue(true);
+  }
+
+  public int getIndex() {
+    return myIndex;
+  }
+
+  public ArrayReference getArray() {
+    return myArray;
+  }
+
+  public String getName() {
+    return String.valueOf(myIndex);
+  }
+
+  public String calcValueName() {
+    return "[" + getName() + "]";
+  }
+
+  public Value calcValue(EvaluationContextImpl evaluationContext) throws EvaluateException {
+    try {
+      return myArray.getValue(myIndex);
+    }
+    catch (ObjectCollectedException e) {
+      throw EvaluateExceptionUtil.ARRAY_WAS_COLLECTED;
+    }
+  }
+
+  public PsiExpression getDescriptorEvaluation(DebuggerContext context) throws EvaluateException {
+    PsiElementFactory elementFactory = JavaPsiFacade.getInstance(context.getProject()).getElementFactory();
+    try {
+      return elementFactory.createExpressionFromText("this[" + myIndex + "]", null);
+    }
+    catch (IncorrectOperationException e) {
+      throw new EvaluateException(e.getMessage(), e);
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/DebuggerTree.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/DebuggerTree.java
new file mode 100644
index 0000000..e80bf60
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/DebuggerTree.java
@@ -0,0 +1,691 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class DebuggerTree
+ * @author Jeka
+ */
+package com.intellij.debugger.ui.impl.watch;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerInvocationUtil;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.SuspendContextImpl;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.engine.events.DebuggerCommandImpl;
+import com.intellij.debugger.engine.events.DebuggerContextCommandImpl;
+import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.debugger.jdi.LocalVariableProxyImpl;
+import com.intellij.debugger.jdi.StackFrameProxyImpl;
+import com.intellij.debugger.jdi.ThreadGroupReferenceProxyImpl;
+import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
+import com.intellij.debugger.settings.NodeRendererSettings;
+import com.intellij.debugger.settings.ThreadsViewSettings;
+import com.intellij.debugger.ui.impl.DebuggerTreeBase;
+import com.intellij.debugger.ui.impl.tree.TreeBuilder;
+import com.intellij.debugger.ui.impl.tree.TreeBuilderNode;
+import com.intellij.debugger.ui.tree.DebuggerTreeNode;
+import com.intellij.debugger.ui.tree.NodeDescriptor;
+import com.intellij.debugger.ui.tree.render.ChildrenBuilder;
+import com.intellij.debugger.ui.tree.render.ClassRenderer;
+import com.intellij.debugger.ui.tree.render.NodeRenderer;
+import com.intellij.openapi.actionSystem.DataKey;
+import com.intellij.openapi.actionSystem.DataProvider;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Key;
+import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.ui.SpeedSearchComparator;
+import com.intellij.ui.TreeSpeedSearch;
+import com.sun.jdi.*;
+
+import javax.swing.*;
+import javax.swing.event.TreeModelEvent;
+import javax.swing.event.TreeModelListener;
+import javax.swing.tree.TreePath;
+import java.awt.*;
+import java.awt.event.MouseEvent;
+import java.util.*;
+import java.util.List;
+
+public abstract class DebuggerTree extends DebuggerTreeBase implements DataProvider {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.impl.watch.DebuggerTree");
+  protected static final Key<Rectangle> VISIBLE_RECT = Key.create("VISIBLE_RECT");
+
+  public static final DataKey<DebuggerTree> DATA_KEY = DataKey.create("DebuggerTree"); 
+
+  protected final NodeManagerImpl myNodeManager;
+
+  private DebuggerContextImpl myDebuggerContext = DebuggerContextImpl.EMPTY_CONTEXT;
+
+  private DebuggerTreeNodeImpl myEditedNode;
+
+  public DebuggerTree(Project project) {
+    super(null, project);
+    setScrollsOnExpand(false);
+    myNodeManager = createNodeManager(project);
+
+    final TreeBuilder model = new TreeBuilder(this) {
+      public void buildChildren(TreeBuilderNode node) {
+        final DebuggerTreeNodeImpl debuggerTreeNode = (DebuggerTreeNodeImpl)node;
+        if (debuggerTreeNode.getDescriptor() instanceof DefaultNodeDescriptor) {
+          return;
+        }
+        buildNode(debuggerTreeNode);
+      }
+
+      public boolean isExpandable(TreeBuilderNode builderNode) {
+        return DebuggerTree.this.isExpandable((DebuggerTreeNodeImpl)builderNode);
+      }
+    };
+    model.setRoot(getNodeFactory().getDefaultNode());
+    model.addTreeModelListener(new TreeModelListener() {
+      public void treeNodesChanged(TreeModelEvent event) {
+        hideTooltip();
+      }
+
+      public void treeNodesInserted(TreeModelEvent event) {
+        hideTooltip();
+      }
+
+      public void treeNodesRemoved(TreeModelEvent event) {
+        hideTooltip();
+      }
+
+      public void treeStructureChanged(TreeModelEvent event) {
+        hideTooltip();
+      }
+    });
+
+    setModel(model);
+
+    final TreeSpeedSearch search = new TreeSpeedSearch(this);
+    search.setComparator(new SpeedSearchComparator(false));
+  }
+
+  protected NodeManagerImpl createNodeManager(Project project) {
+    return new NodeManagerImpl(project, this);
+  }
+
+  public void dispose() {
+    myNodeManager.dispose();
+    myDebuggerContext = DebuggerContextImpl.EMPTY_CONTEXT;
+    super.dispose();
+  }
+
+  protected boolean isExpandable(DebuggerTreeNodeImpl node) {
+    NodeDescriptorImpl descriptor = node.getDescriptor();
+    return descriptor.isExpandable();
+  }
+
+  public Object getData(String dataId) {
+    if (DebuggerTree.DATA_KEY.is(dataId)) {
+      return this;
+    }
+    return null;
+  }
+
+
+  private void buildNode(final DebuggerTreeNodeImpl node) {
+    if (node == null || node.getDescriptor() == null) {
+      return;
+    }
+    final DebugProcessImpl debugProcess = getDebuggerContext().getDebugProcess();
+    if (debugProcess != null) {
+      DebuggerCommandImpl command = getBuildNodeCommand(node);
+      if (command != null) {
+        node.add(myNodeManager.createMessageNode(MessageDescriptor.EVALUATING));
+        debugProcess.getManagerThread().schedule(command);
+      }
+    }
+  }
+
+  // todo: convert "if" into instance method call
+  protected DebuggerCommandImpl getBuildNodeCommand(final DebuggerTreeNodeImpl node) {
+    if (node.getDescriptor() instanceof StackFrameDescriptorImpl) {
+      return new BuildStackFrameCommand(node);
+    }
+    else if (node.getDescriptor() instanceof ValueDescriptorImpl) {
+      return new BuildValueNodeCommand(node);
+    }
+    else if (node.getDescriptor() instanceof StaticDescriptorImpl) {
+      return new BuildStaticNodeCommand(node);
+    }
+    else if (node.getDescriptor() instanceof ThreadDescriptorImpl) {
+      return new BuildThreadCommand(node);
+    }
+    else if (node.getDescriptor() instanceof ThreadGroupDescriptorImpl) {
+      return new BuildThreadGroupCommand(node);
+    }
+    LOG.assertTrue(false);
+    return null;
+  }
+
+  public void saveState(DebuggerTreeNodeImpl node) {
+    if (node.getDescriptor() != null) {
+      TreePath path = new TreePath(node.getPath());
+      node.getDescriptor().myIsExpanded = isExpanded(path);
+      node.getDescriptor().myIsSelected = getSelectionModel().isPathSelected(path);
+      Rectangle rowBounds = getRowBounds(getRowForPath(path));
+      if (rowBounds != null && getVisibleRect().contains(rowBounds)) {
+        node.getDescriptor().putUserData(VISIBLE_RECT, getVisibleRect());
+        node.getDescriptor().myIsVisible = true;
+      }
+      else {
+        node.getDescriptor().putUserData(VISIBLE_RECT, null);
+        node.getDescriptor().myIsVisible = false;
+      }
+    }
+
+    for (Enumeration e = node.rawChildren(); e.hasMoreElements();) {
+      DebuggerTreeNodeImpl child = (DebuggerTreeNodeImpl)e.nextElement();
+      saveState(child);
+    }
+  }
+
+  public void restoreState(DebuggerTreeNodeImpl node) {
+    restoreStateImpl(node);
+    scrollToVisible(node);
+  }
+
+  protected final void scrollToVisible(DebuggerTreeNodeImpl scopeNode) {
+    final TreePath rootPath = new TreePath(scopeNode.getPath());
+    final int rowCount = getRowCount();
+    for (int idx = rowCount - 1; idx >= 0; idx--) {
+      final TreePath treePath = getPathForRow(idx);
+      if (treePath != null) {
+        if (!rootPath.isDescendant(treePath)) {
+          continue;
+        }
+        final DebuggerTreeNodeImpl pathNode = (DebuggerTreeNodeImpl)treePath.getLastPathComponent();
+        final NodeDescriptorImpl descriptor = pathNode.getDescriptor();
+
+        if (descriptor != null && descriptor.myIsVisible) {
+          final Rectangle visibleRect = descriptor.getUserData(VISIBLE_RECT);
+          if (visibleRect != null) {
+            // prefer visible rect
+            scrollRectToVisible(visibleRect);
+          }
+          else {
+            scrollPathToVisible(treePath);
+          }
+          break;
+        }
+      }
+    }
+  }
+
+  public void scrollRectToVisible(Rectangle aRect) {
+    // see IDEADEV-432
+    aRect.width += aRect.x;
+    aRect.x = 0;
+    super.scrollRectToVisible(aRect);
+  }
+
+  private void restoreStateImpl(DebuggerTreeNodeImpl node) {
+    restoreNodeState(node);
+    if (node.getDescriptor().myIsExpanded) {
+      for (Enumeration e = node.rawChildren(); e.hasMoreElements();) {
+        DebuggerTreeNodeImpl child = (DebuggerTreeNodeImpl)e.nextElement();
+        restoreStateImpl(child);
+      }
+    }
+  }
+
+  public void restoreState() {
+    clearSelection();
+    DebuggerTreeNodeImpl root = (DebuggerTreeNodeImpl)getModel().getRoot();
+    if (root != null) {
+      restoreState(root);
+    }
+  }
+
+  protected void restoreNodeState(DebuggerTreeNodeImpl node) {
+    final NodeDescriptorImpl descriptor = node.getDescriptor();
+    if (descriptor != null) {
+      if (node.getParent() == null) {
+        descriptor.myIsExpanded = true;
+      }
+
+      TreePath path = new TreePath(node.getPath());
+      if (descriptor.myIsExpanded) {
+        expandPath(path);
+      }
+      if (descriptor.myIsSelected) {
+        addSelectionPath(path);
+      }
+    }
+  }
+
+  public NodeManagerImpl getNodeFactory() {
+    return myNodeManager;
+  }
+
+  public TreeBuilder getMutableModel() {
+    return (TreeBuilder)getModel();
+  }
+
+  public void removeAllChildren() {
+    DebuggerTreeNodeImpl root = (DebuggerTreeNodeImpl)getModel().getRoot();
+    root.removeAllChildren();
+    treeChanged();
+  }
+
+  public void showMessage(MessageDescriptor messageDesc) {
+    DebuggerTreeNodeImpl root = getNodeFactory().getDefaultNode();
+    getMutableModel().setRoot(root);
+    DebuggerTreeNodeImpl message = root.add(messageDesc);
+    treeChanged();
+    expandPath(new TreePath(message.getPath()));
+  }
+
+  public void showMessage(String messageText) {
+    showMessage(new MessageDescriptor(messageText));
+  }
+
+  public final void treeChanged() {
+    DebuggerTreeNodeImpl node = (DebuggerTreeNodeImpl)getModel().getRoot();
+    if (node != null) {
+      getMutableModel().nodeStructureChanged(node);
+      restoreState();
+    }
+  }
+
+  protected abstract void build(DebuggerContextImpl context);
+
+  protected final void buildWhenPaused(DebuggerContextImpl context, RefreshDebuggerTreeCommand command) {
+    DebuggerSession debuggerSession = context.getDebuggerSession();
+
+    if (ApplicationManager.getApplication().isUnitTestMode() || debuggerSession.getState() == DebuggerSession.STATE_PAUSED) {
+      showMessage(MessageDescriptor.EVALUATING);
+      context.getDebugProcess().getManagerThread().schedule(command);
+    }
+    else {
+      showMessage(context.getDebuggerSession().getStateDescription());
+    }
+  }
+
+  public void rebuild(final DebuggerContextImpl context) {
+    ApplicationManager.getApplication().assertIsDispatchThread();
+    final DebugProcessImpl process = context.getDebugProcess();
+    if (process == null) {
+      return; // empty context, no process available yet
+    }
+    myDebuggerContext = context;
+    saveState();
+    process.getManagerThread().schedule(new DebuggerCommandImpl() {
+      protected void action() throws Exception {
+        getNodeFactory().setHistoryByContext(context);
+      }
+      public Priority getPriority() {
+        return Priority.NORMAL;
+      }
+    });
+
+    build(context);
+  }
+
+  public void saveState() {
+    saveState((DebuggerTreeNodeImpl)getModel().getRoot());
+  }
+
+  public void onEditorShown(DebuggerTreeNodeImpl node) {
+    myEditedNode = node;
+    hideTooltip();
+  }
+
+  public void onEditorHidden(DebuggerTreeNodeImpl node) {
+    if (myEditedNode != null) {
+      assert myEditedNode == node;
+      myEditedNode = null;
+    }
+  }
+
+  @Override
+  public JComponent createToolTip(MouseEvent e) {
+    return myEditedNode != null ? null : super.createToolTip(e);
+  }
+
+  protected abstract static class RefreshDebuggerTreeCommand extends SuspendContextCommandImpl {
+    private final DebuggerContextImpl myDebuggerContext;
+
+    public Priority getPriority() {
+      return Priority.NORMAL;
+    }
+
+    public RefreshDebuggerTreeCommand(DebuggerContextImpl context) {
+      super(context.getSuspendContext());
+      myDebuggerContext = context;
+    }
+
+    public final DebuggerContextImpl getDebuggerContext() {
+      return myDebuggerContext;
+    }
+  }
+
+  public DebuggerContextImpl getDebuggerContext() {
+    return myDebuggerContext;
+  }
+
+  public abstract class BuildNodeCommand extends DebuggerContextCommandImpl {
+    private final DebuggerTreeNodeImpl myNode;
+
+    protected final List<DebuggerTreeNode> myChildren = new LinkedList<DebuggerTreeNode>();
+
+    protected BuildNodeCommand(DebuggerTreeNodeImpl node) {
+      super(DebuggerTree.this.getDebuggerContext());
+      myNode = node;
+    }
+
+    public Priority getPriority() {
+      return Priority.NORMAL;
+    }
+
+    public DebuggerTreeNodeImpl getNode() {
+      return myNode;
+    }
+
+    protected void updateUI(final boolean scrollToVisible) {
+      DebuggerInvocationUtil.swingInvokeLater(getProject(), new Runnable() {
+        public void run() {
+          myNode.removeAllChildren();
+          for (DebuggerTreeNode debuggerTreeNode : myChildren) {
+            myNode.add(debuggerTreeNode);
+          }
+          myNode.childrenChanged(scrollToVisible);
+        }
+      });
+    }
+  }
+
+  protected class BuildStackFrameCommand extends BuildNodeCommand {
+    public BuildStackFrameCommand(DebuggerTreeNodeImpl stackNode) {
+      super(stackNode);
+    }
+
+    public final void threadAction() {
+      try {
+        final StackFrameDescriptorImpl stackDescriptor = (StackFrameDescriptorImpl)getNode().getDescriptor();
+        final StackFrameProxyImpl frame = stackDescriptor.getFrameProxy();
+        if (frame == null) {
+          return;
+        }
+        final Location location = frame.location();
+
+        final ObjectReference thisObjectReference = frame.thisObject();
+
+        final DebuggerContextImpl debuggerContext = getDebuggerContext();
+        final EvaluationContextImpl evaluationContext = debuggerContext.createEvaluationContext();
+
+        if (!debuggerContext.isEvaluationPossible()) {
+          myChildren.add(myNodeManager.createNode(MessageDescriptor.EVALUATION_NOT_POSSIBLE, evaluationContext));
+        }
+
+        final NodeDescriptor descriptor;
+        if (thisObjectReference != null) {
+          descriptor = myNodeManager.getThisDescriptor(stackDescriptor, thisObjectReference);
+        }
+        else {
+          final ReferenceType type = location.method().declaringType();
+          descriptor = myNodeManager.getStaticDescriptor(stackDescriptor, type);
+        }
+        myChildren.add(myNodeManager.createNode(descriptor, evaluationContext));
+
+        final ClassRenderer classRenderer = NodeRendererSettings.getInstance().getClassRenderer();
+        if (classRenderer.SHOW_VAL_FIELDS_AS_LOCAL_VARIABLES) {
+          if (thisObjectReference != null && evaluationContext.getDebugProcess().getVirtualMachineProxy().canGetSyntheticAttribute())  {
+            final ReferenceType thisRefType = thisObjectReference.referenceType();
+            if (thisRefType instanceof ClassType && thisRefType.equals(location.declaringType()) && thisRefType.name().contains("$")) { // makes sense for nested classes only
+              final ClassType clsType = (ClassType)thisRefType;
+              for (Field field : clsType.fields()) {
+                if (field.isSynthetic() && StringUtil.startsWith(field.name(), FieldDescriptorImpl.OUTER_LOCAL_VAR_FIELD_PREFIX)) {
+                  final FieldDescriptorImpl fieldDescriptor = myNodeManager.getFieldDescriptor(stackDescriptor, thisObjectReference, field);
+                  myChildren.add(myNodeManager.createNode(fieldDescriptor, evaluationContext));
+                }
+              }
+            }
+          }
+        }
+
+        try {
+          buildVariables(stackDescriptor, evaluationContext);
+          if (classRenderer.SORT_ASCENDING) {
+            Collections.sort(myChildren, NodeManagerImpl.getNodeComparator());
+          }
+        }
+        catch (EvaluateException e) {
+          myChildren.add(myNodeManager.createMessageNode(new MessageDescriptor(e.getMessage())));
+        }
+        // add last method return value if any
+        final Pair<Method, Value> methodValuePair = debuggerContext.getDebugProcess().getLastExecutedMethod();
+        if (methodValuePair != null) {
+          final ValueDescriptorImpl returnValueDescriptor =
+            myNodeManager.getMethodReturnValueDescriptor(stackDescriptor, methodValuePair.getFirst(), methodValuePair.getSecond());
+          final DebuggerTreeNodeImpl methodReturnValueNode = myNodeManager.createNode(returnValueDescriptor, evaluationContext);
+          myChildren.add(1, methodReturnValueNode);
+        }
+      }
+      catch (EvaluateException e) {
+        myChildren.clear();
+        myChildren.add(myNodeManager.createMessageNode(new MessageDescriptor(e.getMessage())));
+      }
+      catch (InvalidStackFrameException e) {
+        LOG.info(e);
+        myChildren.clear();
+        notifyCancelled();
+      }
+      catch (InternalException e) {
+        if (e.errorCode() == 35) {
+          myChildren.add(
+            myNodeManager.createMessageNode(new MessageDescriptor(DebuggerBundle.message("error.corrupt.debug.info", e.getMessage()))));
+        }
+        else {
+          throw e;
+        }
+      }
+
+      updateUI(true);
+    }
+
+    protected void buildVariables(final StackFrameDescriptorImpl stackDescriptor, final EvaluationContextImpl evaluationContext) throws EvaluateException {
+      final StackFrameProxyImpl frame = stackDescriptor.getFrameProxy();
+      if (frame != null) {
+        for (final LocalVariableProxyImpl local : frame.visibleVariables()) {
+          final LocalVariableDescriptorImpl localVariableDescriptor = myNodeManager.getLocalVariableDescriptor(stackDescriptor, local);
+          final DebuggerTreeNodeImpl variableNode = myNodeManager.createNode(localVariableDescriptor, evaluationContext);
+          myChildren.add(variableNode);
+        }
+      }
+    }
+  }
+
+  private class BuildValueNodeCommand extends BuildNodeCommand implements ChildrenBuilder {
+    public BuildValueNodeCommand(DebuggerTreeNodeImpl node) {
+      super(node);
+    }
+
+    public void threadAction() {
+      ValueDescriptorImpl descriptor = (ValueDescriptorImpl)getNode().getDescriptor();
+      try {
+        final NodeRenderer renderer = descriptor.getRenderer(getSuspendContext().getDebugProcess());
+        renderer.buildChildren(descriptor.getValue(), this, getDebuggerContext().createEvaluationContext());
+      }
+      catch (ObjectCollectedException e) {
+        getNode().removeAllChildren();
+        getNode().add(getNodeFactory().createMessageNode(
+          new MessageDescriptor(DebuggerBundle.message("error.cannot.build.node.children.object.collected", e.getMessage()))));
+        getNode().childrenChanged(false);
+      }
+    }
+
+    public NodeManagerImpl getNodeManager() {
+
+      return myNodeManager;
+    }
+
+    public NodeManagerImpl getDescriptorManager() {
+      return myNodeManager;
+    }
+
+    public ValueDescriptorImpl getParentDescriptor() {
+      return (ValueDescriptorImpl)getNode().getDescriptor();
+    }
+
+    public void setChildren(final List<DebuggerTreeNode> children) {
+      myChildren.addAll(children);
+      updateUI(false);
+    }
+  }
+
+  private class BuildStaticNodeCommand extends BuildNodeCommand {
+    public BuildStaticNodeCommand(DebuggerTreeNodeImpl node) {
+      super(node);
+    }
+
+    public void threadAction() {
+      final StaticDescriptorImpl sd = (StaticDescriptorImpl)getNode().getDescriptor();
+      final ReferenceType refType = sd.getType();
+      List<Field> fields = refType.allFields();
+      for (Field field : fields) {
+        if (field.isStatic()) {
+          final FieldDescriptorImpl fieldDescriptor = myNodeManager.getFieldDescriptor(sd, null, field);
+          final EvaluationContextImpl evaluationContext = getDebuggerContext().createEvaluationContext();
+          final DebuggerTreeNodeImpl node = myNodeManager.createNode(fieldDescriptor, evaluationContext);
+          myChildren.add(node);
+        }
+      }
+
+      updateUI(true);
+    }
+  }
+
+  private class BuildThreadCommand extends BuildNodeCommand {
+    public BuildThreadCommand(DebuggerTreeNodeImpl threadNode) {
+      super(threadNode);
+    }
+
+    public void threadAction() {
+      ThreadDescriptorImpl threadDescriptor = ((ThreadDescriptorImpl)getNode().getDescriptor());
+      ThreadReferenceProxyImpl threadProxy = threadDescriptor.getThreadReference();
+      if (!threadProxy.isCollected() && getDebuggerContext().getDebugProcess().getSuspendManager().isSuspended(threadProxy)) {
+        int status = threadProxy.status();
+        if (!(status == ThreadReference.THREAD_STATUS_UNKNOWN) &&
+            !(status == ThreadReference.THREAD_STATUS_NOT_STARTED) &&
+            !(status == ThreadReference.THREAD_STATUS_ZOMBIE)) {
+          try {
+            for (StackFrameProxyImpl stackFrame : threadProxy.frames()) {
+              //Method method = stackFrame.location().method();
+              //ToDo :check whether is synthetic if (shouldDisplay(method)) {
+              myChildren.add(myNodeManager.createNode(myNodeManager.getStackFrameDescriptor(threadDescriptor, stackFrame),
+                                                      getDebuggerContext().createEvaluationContext()));
+            }
+          }
+          catch (EvaluateException e) {
+            myChildren.clear();
+            myChildren.add(myNodeManager.createMessageNode(e.getMessage()));
+            LOG.debug(e);
+            //LOG.assertTrue(false);
+            // if we pause during evaluation of this method the exception is thrown
+            //  private static void longMethod(){
+            //    try {
+            //      Thread.sleep(100000);
+            //    } catch (InterruptedException e) {
+            //      e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
+            //    }
+            //  }
+          }
+        }
+      }
+      updateUI(true);
+    }
+  }
+
+  private class BuildThreadGroupCommand extends DebuggerCommandImpl {
+    private final DebuggerTreeNodeImpl myNode;
+    protected final List<DebuggerTreeNode> myChildren = new LinkedList<DebuggerTreeNode>();
+
+    public BuildThreadGroupCommand(DebuggerTreeNodeImpl node) {
+      myNode = node;
+    }
+
+    protected void action() throws Exception {
+      ThreadGroupDescriptorImpl groupDescriptor = (ThreadGroupDescriptorImpl)myNode.getDescriptor();
+      ThreadGroupReferenceProxyImpl threadGroup = groupDescriptor.getThreadGroupReference();
+
+      List<ThreadReferenceProxyImpl> threads = new ArrayList<ThreadReferenceProxyImpl>(threadGroup.threads());
+      Collections.sort(threads, ThreadReferenceProxyImpl.ourComparator);
+
+      final DebuggerContextImpl debuggerContext = getDebuggerContext();
+      final SuspendContextImpl suspendContext = debuggerContext.getSuspendContext();
+      final EvaluationContextImpl evaluationContext = suspendContext != null? debuggerContext.createEvaluationContext() : null;
+
+      boolean showCurrent = ThreadsViewSettings.getInstance().SHOW_CURRENT_THREAD;
+
+      for (final ThreadGroupReferenceProxyImpl group : threadGroup.threadGroups()) {
+        if (group != null) {
+          DebuggerTreeNodeImpl threadNode =
+            myNodeManager.createNode(myNodeManager.getThreadGroupDescriptor(groupDescriptor, group), evaluationContext);
+
+          if (showCurrent && ((ThreadGroupDescriptorImpl)threadNode.getDescriptor()).isCurrent()) {
+            myChildren.add(0, threadNode);
+          }
+          else {
+            myChildren.add(threadNode);
+          }
+        }
+      }
+
+      ArrayList<DebuggerTreeNodeImpl> threadNodes = new ArrayList<DebuggerTreeNodeImpl>();
+
+      for (ThreadReferenceProxyImpl thread : threads) {
+        if (thread != null) {
+          final DebuggerTreeNodeImpl threadNode = myNodeManager.createNode(myNodeManager.getThreadDescriptor(groupDescriptor, thread), evaluationContext);
+          if (showCurrent && ((ThreadDescriptorImpl)threadNode.getDescriptor()).isCurrent()) {
+            threadNodes.add(0, threadNode);
+          }
+          else {
+            threadNodes.add(threadNode);
+          }
+        }
+      }
+
+      myChildren.addAll(threadNodes);
+
+      updateUI(true);
+    }
+
+    protected void updateUI(final boolean scrollToVisible) {
+      DebuggerInvocationUtil.swingInvokeLater(getProject(), new Runnable() {
+        public void run() {
+          myNode.removeAllChildren();
+          for (DebuggerTreeNode debuggerTreeNode : myChildren) {
+            myNode.add(debuggerTreeNode);
+          }
+          myNode.childrenChanged(scrollToVisible);
+        }
+      });
+    }
+  }
+
+  public void hideTooltip() {
+    myTipManager.hideTooltip();
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/DebuggerTreeInplaceEditor.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/DebuggerTreeInplaceEditor.java
new file mode 100644
index 0000000..26801cc
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/DebuggerTreeInplaceEditor.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.impl.watch;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.xdebugger.impl.ui.tree.TreeInplaceEditor;
+
+import javax.swing.*;
+import javax.swing.tree.TreePath;
+
+public abstract class DebuggerTreeInplaceEditor extends TreeInplaceEditor {
+  private final DebuggerTreeNodeImpl myNode;
+
+  protected Project getProject() {
+    return myNode.getTree().getProject();
+  }
+
+  public DebuggerTreeInplaceEditor(DebuggerTreeNodeImpl node) {
+    myNode = node;
+  }
+
+  protected TreePath getNodePath() {
+    return new TreePath(myNode.getPath());
+  }
+
+  protected JTree getTree() {
+    return myNode.getTree();
+  }
+
+  @Override
+  protected void onShown() {
+    myNode.getTree().onEditorShown(myNode);
+  }
+
+  @Override
+  protected void onHidden() {
+    myNode.getTree().onEditorHidden(myNode);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/DebuggerTreeNodeExpression.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/DebuggerTreeNodeExpression.java
new file mode 100644
index 0000000..56e0208
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/DebuggerTreeNodeExpression.java
@@ -0,0 +1,300 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.impl.watch;
+
+import com.intellij.codeInsight.ChangeContextUtil;
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.codeinsight.RuntimeTypeEvaluator;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.debugger.engine.evaluation.TextWithImportsImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Computable;
+import com.intellij.pom.java.LanguageLevel;
+import com.intellij.psi.*;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.PsiUtil;
+import com.intellij.util.IncorrectOperationException;
+import com.sun.jdi.ObjectReference;
+import com.sun.jdi.ReferenceType;
+import com.sun.jdi.Value;
+
+/**
+ * User: lex
+ * Date: Oct 29, 2003
+ * Time: 9:24:52 PM
+ */
+public class DebuggerTreeNodeExpression {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeExpression");
+
+//  private static PsiExpression beautifyExpression(PsiExpression expression) throws IncorrectOperationException {
+//    final PsiElementFactory elementFactory = expression.getManager().getElementFactory();
+//    final PsiParenthesizedExpression utility = (PsiParenthesizedExpression)elementFactory.createExpressionFromText(
+//      "(expr)", expression.getContext());
+//    utility.getExpression().replace(expression);
+//
+//    PsiRecursiveElementVisitor visitor = new PsiRecursiveElementVisitor() {
+//      @Override public void visitTypeCastExpression(PsiTypeCastExpression expression) {
+//        try {
+//          super.visitTypeCastExpression(expression);
+//
+//          PsiElement parent;
+//          PsiElement toBeReplaced = expression;
+//          for (parent = expression.getParent();
+//               parent instanceof PsiParenthesizedExpression && parent != utility;
+//               parent = parent.getParent()) {
+//            toBeReplaced = parent;
+//          }
+//
+//          if (parent instanceof PsiReferenceExpression) {
+//            PsiReferenceExpression reference = ((PsiReferenceExpression)parent);
+//            //((TypeCast)).member
+//            PsiElement oldResolved = reference.resolve();
+//
+//            if (oldResolved != null) {
+//              PsiReferenceExpression newReference = ((PsiReferenceExpression)reference.copy());
+//              newReference.getQualifierExpression().replace(expression.getOperand());
+//              PsiElement newResolved = newReference.resolve();
+//
+//              if (oldResolved == newResolved) {
+//                toBeReplaced.replace(expression.getOperand());
+//              }
+//              else if (newResolved instanceof PsiMethod && oldResolved instanceof PsiMethod) {
+//                if (isSuperMethod((PsiMethod)newResolved, (PsiMethod)oldResolved)) {
+//                  toBeReplaced.replace(expression.getOperand());
+//                }
+//              }
+//            }
+//          }
+//          else {
+//            toBeReplaced.replace(expression.getOperand());
+//          }
+//        }
+//        catch (IncorrectOperationException e) {
+//          throw new IncorrectOperationRuntimeException(e);
+//        }
+//      }
+//
+//      @Override public void visitReferenceExpression(PsiReferenceExpression expression) {
+//        expression.acceptChildren(this);
+//
+//        try {
+//          JavaResolveResult resolveResult = expression.advancedResolve(false);
+//
+//          PsiElement oldResolved = resolveResult.getElement();
+//
+//          if(oldResolved == null) return;
+//
+//          PsiReferenceExpression newReference;
+//          if (expression instanceof PsiMethodCallExpression) {
+//            int length = expression.getQualifierExpression().getTextRange().getLength();
+//            PsiMethodCallExpression methodCall = (PsiMethodCallExpression)elementFactory.createExpressionFromText(
+//              expression.getText().substring(length), expression.getContext());
+//            newReference = methodCall.getMethodExpression();
+//          }
+//          else {
+//            newReference =
+//            (PsiReferenceExpression)elementFactory.createExpressionFromText(expression.getReferenceName(),
+//                                                                            expression.getContext());
+//          }
+//
+//          PsiElement newResolved = newReference.resolve();
+//          if (oldResolved == newResolved) {
+//            expression.replace(newReference);
+//          }
+//        }
+//        catch (IncorrectOperationException e) {
+//          LOG.debug(e);
+//        }
+//      }
+//    };
+//
+//    try {
+//      utility.accept(visitor);
+//    }
+//    catch (IncorrectOperationRuntimeException e) {
+//      throw e.getException();
+//    }
+//    return utility.getExpression();
+//  }
+
+  private static boolean isSuperMethod(PsiMethod superMethod, PsiMethod overridingMethod) {
+    PsiMethod[] superMethods = overridingMethod.findSuperMethods();
+      for (int i = 0; i < superMethods.length; i++) {
+        if (superMethods[i] == superMethod) {
+          return true;
+        }
+        else if (isSuperMethod(superMethod, superMethods[i])) {
+          return true;
+        }
+      }
+      return false;
+    }
+
+  public static PsiExpression substituteThis(PsiExpression expressionWithThis, PsiExpression howToEvaluateThis, Value howToEvaluateThisValue)
+    throws EvaluateException {
+    PsiExpression result = (PsiExpression)expressionWithThis.copy();
+
+    PsiClass thisClass = PsiTreeUtil.getContextOfType(result, PsiClass.class, true);
+
+    boolean castNeeded = true;
+
+    if (thisClass != null) {
+      PsiType type = howToEvaluateThis.getType();
+      if(type != null) {
+        if(type instanceof PsiClassType) {
+          PsiClass psiClass = ((PsiClassType) type).resolve();
+          if(psiClass != null && (psiClass == thisClass || psiClass.isInheritor(thisClass, true))) {
+            castNeeded = false;
+          }
+        }
+        else if(type instanceof PsiArrayType) {
+          LanguageLevel languageLevel = PsiUtil.getLanguageLevel(expressionWithThis);
+          if(thisClass == JavaPsiFacade.getInstance(expressionWithThis.getProject()).getElementFactory().getArrayClass(languageLevel)) {
+            castNeeded = false;
+          }
+        }
+      }
+    }
+
+    if (castNeeded) {
+      howToEvaluateThis = castToRuntimeType(howToEvaluateThis, howToEvaluateThisValue, howToEvaluateThis.getContext());
+    }
+
+    ChangeContextUtil.encodeContextInfo(result, false);
+    PsiExpression psiExpression;
+    try {
+      psiExpression = (PsiExpression) ChangeContextUtil.decodeContextInfo(result, thisClass, howToEvaluateThis);
+    }
+    catch (IncorrectOperationException e) {
+      throw new EvaluateException(
+        DebuggerBundle.message("evaluation.error.invalid.this.expression", result.getText(), howToEvaluateThis.getText()), null);
+    }
+
+    try {
+      return JavaPsiFacade.getInstance(howToEvaluateThis.getProject()).getElementFactory()
+        .createExpressionFromText(psiExpression.getText(), howToEvaluateThis.getContext());
+    }
+    catch (IncorrectOperationException e) {
+      throw new EvaluateException(e.getMessage(), e);
+    }
+  }
+
+  public static PsiExpression castToRuntimeType(PsiExpression expression, Value value, PsiElement contextElement) throws EvaluateException {
+    if (!(value instanceof ObjectReference)) {
+      return expression;
+    }
+    
+    ReferenceType valueType = ((ObjectReference)value).referenceType();
+    if (valueType == null) {
+      return expression;
+    }
+    
+    Project project = expression.getProject();
+
+    PsiClass type = RuntimeTypeEvaluator.getCastableRuntimeType(project, value);
+    if (type == null) {
+      return expression;
+    }
+
+    PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project);
+    try {
+      PsiParenthesizedExpression parenthExpression = (PsiParenthesizedExpression)elementFactory.createExpressionFromText(
+        "((" + type.getQualifiedName() + ")expression)", null);
+      ((PsiTypeCastExpression)parenthExpression.getExpression()).getOperand().replace(expression);
+      return parenthExpression;
+    }
+    catch (IncorrectOperationException e) {
+      throw new EvaluateException(DebuggerBundle.message("error.invalid.type.name", type.getQualifiedName()), e);
+    }
+  }
+
+  /**
+   * @param qualifiedName the class qualified name to be resolved against the current execution context
+   * @return short name if the class could be resolved using short name,
+   * otherwise returns qualifiedName
+   */
+  public static String normalize(final String qualifiedName, PsiElement contextElement, Project project) {
+    if (contextElement == null) {
+      return qualifiedName;
+    }
+
+    final JavaPsiFacade facade = JavaPsiFacade.getInstance(project);
+    PsiClass aClass = facade.findClass(qualifiedName, GlobalSearchScope.allScope(project));
+    if (aClass != null) {
+      return normalizePsiClass(aClass, contextElement, facade.getResolveHelper());
+    }
+    return qualifiedName;
+  }
+
+  private static String normalizePsiClass(PsiClass psiClass, PsiElement contextElement, PsiResolveHelper helper) {
+    String name = psiClass.getName();
+    PsiClass aClass = helper.resolveReferencedClass(name, contextElement);
+    if (psiClass.equals(aClass)) {
+      return name;
+    }
+    PsiClass parentClass = psiClass.getContainingClass();
+    if (parentClass != null) {
+      return normalizePsiClass(parentClass, contextElement, helper) + "." + name;
+    }
+    return psiClass.getQualifiedName();
+  }
+
+  public static PsiExpression getEvaluationExpression(DebuggerTreeNodeImpl node, DebuggerContextImpl context) throws EvaluateException {
+    if(node.getDescriptor() instanceof ValueDescriptorImpl) {
+      return ((ValueDescriptorImpl)node.getDescriptor()).getTreeEvaluation(node, context);
+    }
+    else {
+      LOG.error(node.getDescriptor() != null ? node.getDescriptor().getClass().getName() : "null");
+      return null;
+    }
+  }
+
+  public static TextWithImports createEvaluationText(final DebuggerTreeNodeImpl node, final DebuggerContextImpl context) throws EvaluateException {
+    final EvaluateException[] ex = new EvaluateException[] {null};
+    final TextWithImports textWithImports = PsiDocumentManager.getInstance(context.getProject()).commitAndRunReadAction(new Computable<TextWithImports>() {
+      public TextWithImports compute() {
+        try {
+          final PsiExpression expressionText = getEvaluationExpression(node, context);
+          if (expressionText != null) {
+            return new TextWithImportsImpl(expressionText);
+          }
+        }
+        catch (EvaluateException e) {
+          ex[0] = e;
+        }
+        return null;
+      }
+    });
+    if (ex[0] != null) {
+      throw ex[0];
+    }
+    return textWithImports;
+  }
+
+  private static class IncorrectOperationRuntimeException extends RuntimeException {
+    private final IncorrectOperationException myException;
+
+    public IncorrectOperationRuntimeException(IncorrectOperationException exception) {
+      myException = exception;
+    }
+
+    public IncorrectOperationException getException() { return myException; }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/DebuggerTreeNodeImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/DebuggerTreeNodeImpl.java
new file mode 100644
index 0000000..665a6a1
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/DebuggerTreeNodeImpl.java
@@ -0,0 +1,266 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class DebuggerTreeNodeImpl
+ * @author Jeka
+ */
+package com.intellij.debugger.ui.impl.watch;
+
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.engine.events.DebuggerContextCommandImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.ui.impl.DebuggerTreeRenderer;
+import com.intellij.debugger.ui.impl.tree.TreeBuilder;
+import com.intellij.debugger.ui.impl.tree.TreeBuilderNode;
+import com.intellij.debugger.ui.tree.DebuggerTreeNode;
+import com.intellij.debugger.ui.tree.NodeDescriptor;
+import com.intellij.debugger.ui.tree.ValueDescriptor;
+import com.intellij.xdebugger.impl.ui.tree.ValueMarkup;
+import com.intellij.debugger.ui.tree.render.DescriptorLabelListener;
+import com.intellij.debugger.ui.tree.render.NodeRenderer;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Key;
+import com.intellij.ui.SimpleColoredText;
+import com.intellij.util.containers.HashMap;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.util.Map;
+
+public class DebuggerTreeNodeImpl extends TreeBuilderNode implements DebuggerTreeNode{
+  private Icon myIcon;
+  private SimpleColoredText myText;
+  private String myMarkupTooltipText;
+  private final DebuggerTree myTree;
+  private final Map myProperties = new HashMap();
+
+  private DebuggerTreeNodeImpl(DebuggerTree tree, NodeDescriptor descriptor) {
+    super(descriptor);
+    myTree = tree;
+  }
+
+  public DebuggerTreeNodeImpl getParent() {
+    return (DebuggerTreeNodeImpl) super.getParent();
+  }
+
+  protected TreeBuilder getTreeBuilder() {
+    return myTree.getMutableModel();
+  }
+
+  public DebuggerTree getTree() {
+    return myTree;
+  }
+
+  public String toString() {
+    return myText != null? myText.toString() : "";
+  }
+
+  public NodeDescriptorImpl getDescriptor() {
+    return (NodeDescriptorImpl)getUserObject();
+  }
+
+  public Project getProject() {
+    return getTree().getProject();
+  }
+
+  public void setRenderer(NodeRenderer renderer) {
+    ((ValueDescriptorImpl) getDescriptor()).setRenderer(renderer);
+    calcRepresentation();
+  }
+
+  private void updateCaches() {
+    final NodeDescriptorImpl descriptor = getDescriptor();
+    myIcon = DebuggerTreeRenderer.getDescriptorIcon(descriptor);
+    final DebuggerContextImpl context = getTree().getDebuggerContext();
+    myText = DebuggerTreeRenderer.getDescriptorText(context, descriptor, false);
+    if (descriptor instanceof ValueDescriptor) {
+      final ValueMarkup markup = ((ValueDescriptor)descriptor).getMarkup(context.getDebugProcess());
+      myMarkupTooltipText = markup != null? markup.getToolTipText() : null;
+    }
+    else {
+      myMarkupTooltipText = null;
+    }
+  }
+
+  public Icon getIcon() {
+    return myIcon;
+  }
+
+  public SimpleColoredText getText() {
+    return myText;
+  }
+
+  @Nullable
+  public String getMarkupTooltipText() {
+    return myMarkupTooltipText;
+  }
+
+  public void clear() {
+    removeAllChildren();
+    myIcon = null;
+    myText = null;
+    super.clear();
+  }
+
+  private void update(final DebuggerContextImpl context, final Runnable runnable, boolean labelOnly) {
+    if(!labelOnly) {
+      clear();
+    }
+
+    if(context != null && context.getDebugProcess() != null) {
+      getTree().saveState(this);
+
+      myIcon = DebuggerTreeRenderer.getDescriptorIcon(MessageDescriptor.EVALUATING);
+      myText = DebuggerTreeRenderer.getDescriptorText(context, MessageDescriptor.EVALUATING, false);
+
+      context.getDebugProcess().getManagerThread().invoke(new DebuggerContextCommandImpl(context) {
+        public void threadAction() {
+          runnable.run();
+        }
+
+        protected void commandCancelled() {
+          clear();
+          getDescriptor().clear();
+          updateCaches();
+
+          labelChanged();
+          childrenChanged(true);
+        }
+        public Priority getPriority() {
+          return Priority.NORMAL;
+        }
+
+      });
+    }
+
+    labelChanged();
+    if(!labelOnly) {
+      childrenChanged(true);
+    }
+  }
+
+  public void calcLabel() {
+    final DebuggerContextImpl context = getTree().getDebuggerContext();
+    update(context, new Runnable() {
+      public void run() {
+        getDescriptor().updateRepresentation(context.createEvaluationContext(), new DescriptorLabelListener() {
+          public void labelChanged() {
+            updateCaches();
+            DebuggerTreeNodeImpl.this.labelChanged();
+          }
+        });
+      }
+    }, true);
+  }
+
+  public void calcRepresentation() {
+    final DebuggerContextImpl context = getTree().getDebuggerContext();
+    update(context, new Runnable() {
+      public void run() {
+        getDescriptor().updateRepresentation(context.createEvaluationContext(), new DescriptorLabelListener() {
+          public void labelChanged() {
+            updateCaches();
+            DebuggerTreeNodeImpl.this.labelChanged();
+          }
+        });
+      }
+    }, false);
+  }
+
+  public void calcValue() {
+    final DebuggerContextImpl context = getTree().getDebuggerContext();
+    update(
+      context,
+      new Runnable() {
+        public void run() {
+          EvaluationContextImpl evaluationContext = context.createEvaluationContext();
+          getDescriptor().setContext(evaluationContext);
+          getDescriptor().updateRepresentation(evaluationContext, new DescriptorLabelListener() {
+            public void labelChanged() {
+              updateCaches();
+              DebuggerTreeNodeImpl.this.labelChanged();
+            }
+          });
+          DebuggerTreeNodeImpl.this.childrenChanged(true);
+        }
+      }, false);
+  }
+
+  private void invoke(Runnable r) {
+    if(ApplicationManager.getApplication().isDispatchThread()) {
+      r.run();
+    }
+    else {
+      SwingUtilities.invokeLater(r);
+    }
+  }
+
+  public void labelChanged() {
+    invoke(new Runnable() {
+      public void run() {
+        updateCaches();
+        getTree().getMutableModel().nodeChanged(DebuggerTreeNodeImpl.this);
+      }
+    });
+  }
+
+  public void childrenChanged(final boolean scrollToVisible) {
+    invoke(new Runnable() {
+      public void run() {
+        getTree().getMutableModel().nodeStructureChanged(DebuggerTreeNodeImpl.this);
+        getTree().restoreState(DebuggerTreeNodeImpl.this);
+      }
+    });
+  }
+
+  public DebuggerTreeNodeImpl add(MessageDescriptor message) {
+    DebuggerTreeNodeImpl node = getNodeFactory().createMessageNode(message);
+    add(node);
+    return node;
+  }
+
+  public NodeManagerImpl getNodeFactory() {
+    return myTree.getNodeFactory();
+  }
+
+  public Object getProperty(Key key) {
+    return myProperties.get(key);
+  }
+
+  public void putProperty(Key key, Object data) {
+    myProperties.put(key, data);
+  }
+
+  public static DebuggerTreeNodeImpl createNodeNoUpdate(DebuggerTree tree, NodeDescriptor descriptor) {
+    DebuggerTreeNodeImpl node = new DebuggerTreeNodeImpl(tree, descriptor);
+    node.updateCaches();
+    return node;
+  }
+
+  protected static DebuggerTreeNodeImpl createNode(DebuggerTree tree, NodeDescriptorImpl descriptor, EvaluationContextImpl evaluationContext) {
+    final DebuggerTreeNodeImpl node = new DebuggerTreeNodeImpl(tree, descriptor);
+    descriptor.updateRepresentationNoNotify(evaluationContext, new DescriptorLabelListener() {
+      public void labelChanged() {
+        node.updateCaches();
+        node.labelChanged();
+      }
+    });
+    node.updateCaches();
+    return node;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/DefaultNodeDescriptor.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/DefaultNodeDescriptor.java
new file mode 100644
index 0000000..ba86515
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/DefaultNodeDescriptor.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * @author Eugene Zhuravlev
+ */
+package com.intellij.debugger.ui.impl.watch;
+
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.ui.tree.render.DescriptorLabelListener;
+import com.intellij.openapi.diagnostic.Logger;
+
+
+public final class DefaultNodeDescriptor extends NodeDescriptorImpl{
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.impl.watch.DefaultNodeDescriptor");
+  public boolean equals(Object obj) {
+    return obj instanceof DefaultNodeDescriptor;
+  }
+
+  public int hashCode() {
+    return 0;
+  }
+
+  public boolean isExpandable() {
+    return true;
+  }
+
+  public void setContext(EvaluationContextImpl context) {
+  }
+
+  protected String calcRepresentation(EvaluationContextImpl context, DescriptorLabelListener labelListener) {
+    LOG.assertTrue(false);
+    return null;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/DescriptorTree.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/DescriptorTree.java
new file mode 100644
index 0000000..5dd5acb
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/DescriptorTree.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.impl.watch;
+
+import com.intellij.debugger.ui.tree.NodeDescriptor;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+
+public class DescriptorTree {
+  private final HashMap<NodeDescriptor, List<NodeDescriptor>> myChildrenMap = new HashMap<NodeDescriptor, List<NodeDescriptor>>();
+  private final List<NodeDescriptor> myRootChildren = new ArrayList<NodeDescriptor>();
+  private final boolean myInitial;
+  private int myFrameCount = -1;
+  private int myFrameIndex = -1;
+
+  public DescriptorTree() {
+    this(false);
+  }
+
+  public DescriptorTree(boolean isInitial) {
+    myInitial = isInitial;
+  }
+
+  public void clear() {
+    myChildrenMap.clear();
+    myRootChildren.clear();
+  }
+
+  public boolean frameIdEquals(final int frameCount, final int frameIndex) {
+    return myFrameCount == frameCount && myFrameIndex == frameIndex;
+  }
+
+  public void setFrameId(final int frameCount, final int frameIndex) {
+    myFrameIndex = frameIndex;
+    myFrameCount = frameCount;
+  }
+
+  public void addChild(NodeDescriptor parent, NodeDescriptor child) {
+    List<NodeDescriptor> children;
+
+    if(parent == null) {
+      children = myRootChildren;
+    }
+    else {
+      children = myChildrenMap.get(parent);
+      if(children == null) {
+        children = new ArrayList<NodeDescriptor>();
+        myChildrenMap.put(parent, children);
+      }
+    }
+    children.add(child);
+    if (myInitial && child instanceof LocalVariableDescriptorImpl) {
+      ((LocalVariableDescriptorImpl)child).setNewLocal(false);
+    }
+  }
+
+  public List<NodeDescriptor> getChildren(NodeDescriptor parent) {
+    if(parent == null) {
+      return myRootChildren;
+    }
+
+    List<NodeDescriptor> children = myChildrenMap.get(parent);
+    return children != null ? children : Collections.<NodeDescriptor>emptyList();
+  }
+
+  public void dfst(DFSTWalker walker) {
+    dfstImpl(null, myRootChildren, walker);
+  }
+
+  private void dfstImpl(NodeDescriptor descriptor, List<NodeDescriptor> children, DFSTWalker walker) {
+    if(children != null) {
+      for (NodeDescriptor child : children) {
+        walker.visit(descriptor, child);
+        dfstImpl(child, myChildrenMap.get(child), walker);
+      }
+    }
+  }
+
+  public interface DFSTWalker {
+    void visit(NodeDescriptor parent, NodeDescriptor child);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/EvaluationDescriptor.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/EvaluationDescriptor.java
new file mode 100644
index 0000000..e09c17c
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/EvaluationDescriptor.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2000-2011 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.debugger.ui.impl.watch;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerContext;
+import com.intellij.debugger.DebuggerInvocationUtil;
+import com.intellij.debugger.EvaluatingComputable;
+import com.intellij.debugger.engine.ContextUtil;
+import com.intellij.debugger.engine.StackFrameContext;
+import com.intellij.debugger.engine.evaluation.*;
+import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator;
+import com.intellij.debugger.engine.evaluation.expression.Modifier;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.impl.PositionUtil;
+import com.intellij.debugger.jdi.StackFrameProxyImpl;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiCodeFragment;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiExpression;
+import com.intellij.psi.PsiExpressionCodeFragment;
+import com.sun.jdi.ObjectReference;
+import com.sun.jdi.Value;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author lex
+ */
+public abstract class EvaluationDescriptor extends ValueDescriptorImpl{
+  private Modifier myModifier;
+  protected TextWithImports myText;
+  private CodeFragmentFactory myCodeFragmentFactory = null; // used to force specific context, e.g. from evaluation
+
+  protected EvaluationDescriptor(TextWithImports text, Project project, Value value) {
+    super(project, value);
+    myText = text;
+  }
+
+  protected EvaluationDescriptor(TextWithImports text, Project project) {
+    super(project);
+    setLvalue(false);
+    myText = text;
+  }
+
+  public final void setCodeFragmentFactory(CodeFragmentFactory codeFragmentFactory) {
+    myCodeFragmentFactory = codeFragmentFactory != null? new CodeFragmentFactoryContextWrapper(codeFragmentFactory) : null;
+  }
+
+  @Nullable
+  public final CodeFragmentFactory getCodeFragmentFactory() {
+    return myCodeFragmentFactory;
+  }
+
+  protected final @NotNull CodeFragmentFactory getEffectiveCodeFragmentFactory(final PsiElement psiContext) {
+    if (myCodeFragmentFactory != null) {
+      return myCodeFragmentFactory;
+    }
+    return DebuggerUtilsEx.getEffectiveCodeFragmentFactory(psiContext);
+  }
+
+  protected abstract EvaluationContextImpl getEvaluationContext (EvaluationContextImpl evaluationContext);
+
+  protected abstract PsiCodeFragment getEvaluationCode(StackFrameContext context) throws EvaluateException;
+
+  public final Value calcValue(final EvaluationContextImpl evaluationContext) throws EvaluateException {
+    try {
+      final EvaluationContextImpl thisEvaluationContext = getEvaluationContext(evaluationContext);
+
+      final ExpressionEvaluator evaluator = DebuggerInvocationUtil.commitAndRunReadAction(myProject, new EvaluatingComputable<ExpressionEvaluator>() {
+        public ExpressionEvaluator compute() throws EvaluateException {
+          final PsiElement psiContext = PositionUtil.getContextElement(evaluationContext);
+          return getEffectiveCodeFragmentFactory(psiContext).getEvaluatorBuilder().build(getEvaluationCode(thisEvaluationContext),
+                                                            ContextUtil.getSourcePosition(thisEvaluationContext));
+        }
+      });
+
+
+      if (!thisEvaluationContext.getDebugProcess().isAttached()) {
+        throw EvaluateExceptionUtil.PROCESS_EXITED;
+      }
+      StackFrameProxyImpl frameProxy = thisEvaluationContext.getFrameProxy();
+      if (frameProxy == null) {
+        throw EvaluateExceptionUtil.NULL_STACK_FRAME;
+      }
+
+      final Value value = evaluator.evaluate(thisEvaluationContext);
+      if (value instanceof ObjectReference) {
+        thisEvaluationContext.getSuspendContext().keep(((ObjectReference)value));
+      }
+      myModifier = evaluator.getModifier();
+      setLvalue(myModifier != null);
+
+      return value;
+    }
+    catch (final EvaluateException ex) {
+      throw new EvaluateException(ex.getLocalizedMessage(), ex);
+    }
+  }
+
+  public String calcValueName() {
+    return getName();
+  }
+
+  public PsiExpression getDescriptorEvaluation(DebuggerContext context) throws EvaluateException {
+    PsiElement evaluationCode = getEvaluationCode(context);
+    if(evaluationCode instanceof PsiExpressionCodeFragment) {
+      return ((PsiExpressionCodeFragment)evaluationCode).getExpression();
+    }
+    else {
+      throw new EvaluateException(DebuggerBundle.message("error.cannot.create.expression.from.code.fragment"), null);
+    }
+  }
+
+  public Modifier getModifier() {
+    return myModifier;
+  }
+
+  public boolean canSetValue() {
+    return super.canSetValue() && myModifier != null && myModifier.canSetValue();
+  }
+
+  public TextWithImports getEvaluationText() {
+    return myText;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/FieldDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/FieldDescriptorImpl.java
new file mode 100644
index 0000000..97e1c45
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/FieldDescriptorImpl.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.impl.watch;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerContext;
+import com.intellij.debugger.SourcePosition;
+import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
+import com.intellij.debugger.engine.DebuggerUtils;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.PositionUtil;
+import com.intellij.debugger.settings.NodeRendererSettings;
+import com.intellij.debugger.ui.tree.FieldDescriptor;
+import com.intellij.debugger.ui.tree.NodeDescriptor;
+import com.intellij.debugger.ui.tree.render.ClassRenderer;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.*;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.util.IncorrectOperationException;
+import com.intellij.util.StringBuilderSpinAllocator;
+import com.sun.jdi.*;
+import org.jetbrains.annotations.NotNull;
+
+public class FieldDescriptorImpl extends ValueDescriptorImpl implements FieldDescriptor{
+  public static final String OUTER_LOCAL_VAR_FIELD_PREFIX = "val$";
+  private final Field myField;
+  private final ObjectReference myObject;
+  private Boolean myIsPrimitive = null;
+  private final boolean myIsStatic;
+
+  public FieldDescriptorImpl(Project project, ObjectReference objRef, @NotNull Field field) {
+    super(project);
+    myObject = objRef;
+    myField = field;
+    myIsStatic = field.isStatic();
+    setLvalue(!field.isFinal());
+  }
+
+  public Field getField() {
+    return myField;
+  }
+
+  public ObjectReference getObject() {
+    return myObject;
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  public SourcePosition getSourcePosition(final Project project, final DebuggerContextImpl context) {
+    if (context.getFrameProxy() == null) return null;
+    final ReferenceType type = myField.declaringType();
+    final JavaPsiFacade facade = JavaPsiFacade.getInstance(project);
+    final String fieldName = myField.name();
+    if (fieldName.startsWith(OUTER_LOCAL_VAR_FIELD_PREFIX)) {
+      // this field actually mirrors a local variable in the outer class
+      String varName = fieldName.substring(fieldName.lastIndexOf('$') + 1);
+      PsiElement element = PositionUtil.getContextElement(context);
+      if (element == null) {
+        return null;
+      }
+      PsiClass aClass = PsiTreeUtil.getParentOfType(element, PsiClass.class, false);
+      if (aClass == null) {
+        return null;
+      }
+      aClass = (PsiClass) aClass.getNavigationElement();
+      PsiVariable psiVariable = facade.getResolveHelper().resolveReferencedVariable(varName, aClass);
+      if (psiVariable == null) {
+        return null;
+      }
+      return SourcePosition.createFromOffset(psiVariable.getContainingFile(), psiVariable.getTextOffset());
+    }
+    else {
+      PsiClass aClass =
+        facade.findClass(type.name().replace('$', '.'), GlobalSearchScope.allScope(myProject));
+      if (aClass == null) return null;
+      aClass = (PsiClass) aClass.getNavigationElement();
+      PsiField[] fields = aClass.getFields();
+      for (PsiField field : fields) {
+        if (fieldName.equals(field.getName())) {
+          return SourcePosition.createFromOffset(field.getContainingFile(), field.getTextOffset());
+        }
+      }
+      return null;
+    }
+  }
+
+  public void setAncestor(NodeDescriptor oldDescriptor) {
+    super.setAncestor(oldDescriptor);
+    final Boolean isPrimitive = ((FieldDescriptorImpl)oldDescriptor).myIsPrimitive;
+    if (isPrimitive != null) { // was cached
+      // do not loose cached info
+      myIsPrimitive = isPrimitive;
+    }
+  }
+
+
+  public boolean isPrimitive() {
+    if (myIsPrimitive == null) {
+      final Value value = getValue();
+      if (value != null) {
+        myIsPrimitive = super.isPrimitive();
+      }
+      else {
+        myIsPrimitive = DebuggerUtils.isPrimitiveType(myField.typeName()) ? Boolean.TRUE : Boolean.FALSE;
+      }
+    }
+    return myIsPrimitive.booleanValue();
+  }
+
+  public Value calcValue(EvaluationContextImpl evaluationContext) throws EvaluateException {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    try {
+      return (myObject != null) ? myObject.getValue(myField) : myField.declaringType().getValue(myField);
+    }
+    catch (ObjectCollectedException e) {
+      throw EvaluateExceptionUtil.OBJECT_WAS_COLLECTED;
+    }
+  }
+
+  public boolean isStatic() {
+    return myIsStatic;
+  }
+
+  public String getName() {
+    final String fieldName = myField.name();
+    if (isOuterLocalVariableValue() && NodeRendererSettings.getInstance().getClassRenderer().SHOW_VAL_FIELDS_AS_LOCAL_VARIABLES) {
+      return StringUtil.trimStart(fieldName, OUTER_LOCAL_VAR_FIELD_PREFIX);
+    }
+    return fieldName;
+  }
+
+  public boolean isOuterLocalVariableValue() {
+    try {
+      return DebuggerUtils.isSynthetic(myField) && myField.name().startsWith(OUTER_LOCAL_VAR_FIELD_PREFIX);
+    }
+    catch (UnsupportedOperationException e) {
+      return false;
+    }
+  }
+
+  public String calcValueName() {
+    final ClassRenderer classRenderer = NodeRendererSettings.getInstance().getClassRenderer();
+    StringBuilder buf = StringBuilderSpinAllocator.alloc();
+    try {
+      buf.append(getName());
+      if (classRenderer.SHOW_DECLARED_TYPE) {
+        buf.append(": ");
+        buf.append(classRenderer.renderTypeName(myField.typeName()));
+      }
+      return buf.toString();
+    }
+    finally {
+      StringBuilderSpinAllocator.dispose(buf);
+    }
+  }
+
+  public PsiExpression getDescriptorEvaluation(DebuggerContext context) throws EvaluateException {
+    PsiElementFactory elementFactory = JavaPsiFacade.getInstance(context.getProject()).getElementFactory();
+    String fieldName;
+    if(isStatic()) {
+      String typeName = myField.declaringType().name().replace('$', '.');
+      typeName = DebuggerTreeNodeExpression.normalize(typeName, PositionUtil.getContextElement(context), context.getProject());
+      fieldName = typeName + "." + getName();
+    }
+    else {
+      //noinspection HardCodedStringLiteral
+      fieldName = isOuterLocalVariableValue()? StringUtil.trimStart(getName(), OUTER_LOCAL_VAR_FIELD_PREFIX) : "this." + getName();
+    }
+    try {
+      return elementFactory.createExpressionFromText(fieldName, null);
+    }
+    catch (IncorrectOperationException e) {
+      throw new EvaluateException(DebuggerBundle.message("error.invalid.field.name", getName()), e);
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/LocalVariableDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/LocalVariableDescriptorImpl.java
new file mode 100644
index 0000000..96f0dc6
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/LocalVariableDescriptorImpl.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.impl.watch;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerContext;
+import com.intellij.debugger.SourcePosition;
+import com.intellij.debugger.engine.DebuggerUtils;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.impl.PositionUtil;
+import com.intellij.debugger.jdi.LocalVariableProxyImpl;
+import com.intellij.debugger.jdi.StackFrameProxyImpl;
+import com.intellij.debugger.settings.NodeRendererSettings;
+import com.intellij.debugger.ui.tree.LocalVariableDescriptor;
+import com.intellij.debugger.ui.tree.NodeDescriptor;
+import com.intellij.debugger.ui.tree.render.ClassRenderer;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.*;
+import com.intellij.util.IncorrectOperationException;
+import com.intellij.util.StringBuilderSpinAllocator;
+import com.sun.jdi.Value;
+import org.jetbrains.annotations.NotNull;
+
+public class LocalVariableDescriptorImpl extends ValueDescriptorImpl implements LocalVariableDescriptor {
+  private final StackFrameProxyImpl myFrameProxy;
+  private final LocalVariableProxyImpl myLocalVariable;
+
+  private String myTypeName = DebuggerBundle.message("label.unknown.value");
+  private boolean myIsPrimitive;
+
+  private boolean myIsNewLocal = true;
+  private boolean myIsVisible = true;
+
+  public LocalVariableDescriptorImpl(Project project,
+                                     @NotNull LocalVariableProxyImpl local) {
+    super(project);
+    setLvalue(true);
+    myFrameProxy = local.getFrame();
+    myLocalVariable = local;
+  }
+
+  public LocalVariableProxyImpl getLocalVariable() {
+    return myLocalVariable;
+  }
+
+  public SourcePosition getSourcePosition(final Project project, final DebuggerContextImpl context) {
+    StackFrameProxyImpl frame = context.getFrameProxy();
+    if (frame == null) return null;
+
+    PsiElement place = PositionUtil.getContextElement(context);
+
+    if (place == null) {
+      return null;
+    }
+
+    PsiVariable psiVariable = JavaPsiFacade.getInstance(project).getResolveHelper().resolveReferencedVariable(getName(), place);
+    if (psiVariable == null) {
+      return null;
+    }
+
+    PsiFile containingFile = psiVariable.getContainingFile();
+    if(containingFile == null) return null;
+
+    return SourcePosition.createFromOffset(containingFile, psiVariable.getTextOffset());
+  }
+
+  public boolean isNewLocal() {
+    return myIsNewLocal;
+  }
+
+  public boolean isPrimitive() {
+    return myIsPrimitive;
+  }
+
+  public Value calcValue(EvaluationContextImpl evaluationContext) throws EvaluateException {
+    myIsVisible = myFrameProxy.isLocalVariableVisible(getLocalVariable());
+    if (myIsVisible) {
+      final String typeName = getLocalVariable().typeName();
+      myTypeName = typeName;
+      myIsPrimitive = DebuggerUtils.isPrimitiveType(typeName);
+      return myFrameProxy.getValue(getLocalVariable());
+    }
+
+    return null;
+  }
+
+  public void setNewLocal(boolean aNew) {
+    myIsNewLocal = aNew;
+  }
+
+  public void displayAs(NodeDescriptor descriptor) {
+    super.displayAs(descriptor);
+    if(descriptor instanceof LocalVariableDescriptorImpl) {
+      myIsNewLocal = ((LocalVariableDescriptorImpl)descriptor).myIsNewLocal;
+    }
+  }
+
+  public String getName() {
+    return myLocalVariable.name();
+  }
+
+  public String calcValueName() {
+    final ClassRenderer classRenderer = NodeRendererSettings.getInstance().getClassRenderer();
+    StringBuilder buf = StringBuilderSpinAllocator.alloc();
+    try {
+      buf.append(getName());
+      if (classRenderer.SHOW_DECLARED_TYPE) {
+        buf.append(": ");
+        buf.append(classRenderer.renderTypeName(myTypeName));
+      }
+      return buf.toString();
+    }
+    finally {
+      StringBuilderSpinAllocator.dispose(buf);
+    }
+  }
+
+  public PsiExpression getDescriptorEvaluation(DebuggerContext context) throws EvaluateException {
+    PsiElementFactory elementFactory = JavaPsiFacade.getInstance(context.getProject()).getElementFactory();
+    try {
+      return elementFactory.createExpressionFromText(getName(), PositionUtil.getContextElement(context));
+    }
+    catch (IncorrectOperationException e) {
+      throw new EvaluateException(DebuggerBundle.message("error.invalid.local.variable.name", getName()), e);
+    }
+  }
+}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/MarkedDescriptorTree.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/MarkedDescriptorTree.java
new file mode 100644
index 0000000..90203e5
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/MarkedDescriptorTree.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.impl.watch;
+
+import com.intellij.debugger.impl.descriptors.data.DescriptorKey;
+import com.intellij.debugger.ui.tree.NodeDescriptor;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class MarkedDescriptorTree {
+  private final HashMap<NodeDescriptor, Map<DescriptorKey<? extends NodeDescriptor>, NodeDescriptor>> myChildrenMap = new HashMap<NodeDescriptor, Map<DescriptorKey<? extends NodeDescriptor>, NodeDescriptor>>();
+  private final Map<DescriptorKey<? extends NodeDescriptor>, NodeDescriptor> myRootChildren = new com.intellij.util.containers.HashMap<DescriptorKey<? extends NodeDescriptor>, NodeDescriptor>();
+
+  public <T extends NodeDescriptor> void addChild(NodeDescriptor parent, T child, DescriptorKey<T> key) {
+    Map<DescriptorKey<? extends NodeDescriptor>, NodeDescriptor> children;
+
+    if(parent == null) {
+      children = myRootChildren;
+    }
+    else {
+      children = myChildrenMap.get(parent);
+      if(children == null) {
+        children = new com.intellij.util.containers.HashMap<DescriptorKey<? extends NodeDescriptor>, NodeDescriptor>();
+        myChildrenMap.put(parent, children);
+      }
+    }
+    children.put(key, child);
+  }
+
+  public <T extends NodeDescriptor> T getChild(NodeDescriptor parent, DescriptorKey<T> key) {
+    if(parent == null) {
+      return (T)myRootChildren.get(key);
+    }
+    final Map<DescriptorKey<? extends NodeDescriptor>, NodeDescriptor> map = myChildrenMap.get(parent);
+    return (T)(map != null ? map.get(key) : null);
+  }
+
+  public void clear() {
+    myChildrenMap.clear();
+    myRootChildren.clear();
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/MessageDescriptor.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/MessageDescriptor.java
new file mode 100644
index 0000000..026f2ad
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/MessageDescriptor.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.impl.watch;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.ui.tree.render.DescriptorLabelListener;
+import com.intellij.xdebugger.impl.ui.XDebuggerUIConstants;
+
+public class MessageDescriptor extends NodeDescriptorImpl {
+  public static final int ERROR = 0;
+  public static final int WARNING = 1;
+  public static final int INFORMATION = 2;
+  public static final int SPECIAL = 3;
+  private int myKind;
+  private String myMessage;
+
+  public static MessageDescriptor DEBUG_INFO_UNAVAILABLE = new MessageDescriptor(DebuggerBundle.message("message.node.debug.info.not.available"));
+  public static MessageDescriptor LOCAL_VARIABLES_INFO_UNAVAILABLE = new MessageDescriptor(
+    DebuggerBundle.message("message.node.local.variables.debug.info.not.available")
+  );
+  public static MessageDescriptor ALL_ELEMENTS_IN_VISIBLE_RANGE_ARE_NULL = new MessageDescriptor(
+    DebuggerBundle.message("message.node.all.array.elements.null"));
+  public static MessageDescriptor ALL_ELEMENTS_IN_RANGE_ARE_NULL = new MessageDescriptor(
+    DebuggerBundle.message("message.node.all.elements.null"));
+  public static MessageDescriptor ARRAY_IS_EMPTY = new MessageDescriptor(DebuggerBundle.message("message.node.empty.array"));
+  public static MessageDescriptor CLASS_HAS_NO_FIELDS = new MessageDescriptor(DebuggerBundle.message("message.node.class.has.no.fields"));
+  public static MessageDescriptor OBJECT_COLLECTED = new MessageDescriptor(DebuggerBundle.message("message.node.object.collected"));
+  public static MessageDescriptor EVALUATING = new MessageDescriptor(XDebuggerUIConstants.COLLECTING_DATA_MESSAGE);
+  public static MessageDescriptor THREAD_IS_RUNNING = new MessageDescriptor(DebuggerBundle.message("message.node.thread.running"));
+  public static MessageDescriptor THREAD_IS_EMPTY = new MessageDescriptor(DebuggerBundle.message("message.node.thread.has.no.frames"));
+  public static MessageDescriptor EVALUATION_NOT_POSSIBLE = new MessageDescriptor(DebuggerBundle.message("message.node.evaluation.not.possible", WARNING));
+
+  public MessageDescriptor(String message) {
+    this(message, INFORMATION);
+  }
+
+  public MessageDescriptor(String message, int kind) {
+    myKind = kind;
+    myMessage = message;
+  }
+
+  public int getKind() {
+    return myKind;
+  }
+
+  public String getLabel() {
+    return myMessage;
+  }
+
+  public boolean isExpandable() {
+    return false;
+  }
+
+  public void setContext(EvaluationContextImpl context) {
+  }
+
+  protected String calcRepresentation(EvaluationContextImpl context, DescriptorLabelListener labelListener) throws EvaluateException {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    return myMessage;
+  }
+}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/MethodReturnValueDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/MethodReturnValueDescriptorImpl.java
new file mode 100644
index 0000000..2ab0b02
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/MethodReturnValueDescriptorImpl.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.impl.watch;
+
+import com.intellij.debugger.DebuggerContext;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiExpression;
+import com.sun.jdi.ClassNotLoadedException;
+import com.sun.jdi.Method;
+import com.sun.jdi.Type;
+import com.sun.jdi.Value;
+
+/**
+ * User: lex
+ * Date: Oct 8, 2003
+ * Time: 5:08:07 PM
+ */
+public class MethodReturnValueDescriptorImpl extends ValueDescriptorImpl{
+  private final Method myMethod;
+  private final Value myValue;
+
+  public MethodReturnValueDescriptorImpl(Project project, final Method method, Value value) {
+    super(project);
+    myMethod = method;
+    myValue = value;
+  }
+
+  public Value calcValue(EvaluationContextImpl evaluationContext) throws EvaluateException {
+    return myValue;
+  }
+
+  public String getName() {
+    //noinspection HardCodedStringLiteral
+    return myMethod.toString();
+  }
+
+  public String calcValueName() {
+    return getName();
+  }
+
+  public Type getType() {
+    if (myValue == null) {
+      try {
+        return myMethod.returnType();
+      }
+      catch (ClassNotLoadedException ignored) {
+      }
+    }
+    return super.getType();
+  }
+
+  public PsiExpression getDescriptorEvaluation(DebuggerContext context) throws EvaluateException {
+    throw new EvaluateException("Evaluation not supported for method return value");
+  }
+
+  public boolean canSetValue() {
+    return false;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/MethodsTracker.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/MethodsTracker.java
new file mode 100644
index 0000000..8547e48
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/MethodsTracker.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.impl.watch;
+
+import com.sun.jdi.Method;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: Dec 13, 2006
+ */
+public class MethodsTracker {
+  private final Map<Method, Integer> myMethodToOccurrenceMap = new HashMap<Method, Integer>();
+
+  public final class MethodOccurrence {
+    private final Method myMethod;
+    private final int myIndex;
+
+    private MethodOccurrence(Method method, int index) {
+      myMethod = method;
+      myIndex = index;
+    }
+
+    public Method getMethod() {
+      return myMethod;
+    }
+
+    public int getIndex() {
+      return getOccurrenceCount(myMethod) - myIndex;
+    }
+
+    public boolean isRecursive() {
+      return getOccurrenceCount(myMethod) > 1;
+    }
+  }
+
+  public MethodOccurrence getMethodOccurrence(Method method) {
+    return new MethodOccurrence(method, assignOccurrenceIndex(method));
+  }
+
+  private int getOccurrenceCount(Method method) {
+    if (method == null) {
+      return 0;
+    }
+    final Integer integer = myMethodToOccurrenceMap.get(method);
+    return integer != null? integer.intValue(): 0;
+  }
+
+  private int assignOccurrenceIndex(Method method) {
+    if (method == null) {
+      return 0;
+    }
+    final int count = getOccurrenceCount(method);
+    myMethodToOccurrenceMap.put(method, count + 1);
+    return count;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeDescriptorFactoryImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeDescriptorFactoryImpl.java
new file mode 100644
index 0000000..9596b39
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeDescriptorFactoryImpl.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.impl.watch;
+
+import com.intellij.debugger.engine.StackFrameContext;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.debugger.engine.jdi.LocalVariableProxy;
+import com.intellij.debugger.engine.jdi.StackFrameProxy;
+import com.intellij.debugger.engine.jdi.ThreadReferenceProxy;
+import com.intellij.debugger.impl.descriptors.data.*;
+import com.intellij.debugger.jdi.LocalVariableProxyImpl;
+import com.intellij.debugger.jdi.StackFrameProxyImpl;
+import com.intellij.debugger.jdi.ThreadGroupReferenceProxyImpl;
+import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
+import com.intellij.debugger.ui.tree.NodeDescriptor;
+import com.intellij.debugger.ui.tree.NodeDescriptorFactory;
+import com.intellij.debugger.ui.tree.UserExpressionDescriptor;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.sun.jdi.*;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.HashMap;
+
+public class NodeDescriptorFactoryImpl implements NodeDescriptorFactory {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.impl.watch.NodeDescriptorFactoryImpl");
+  private DescriptorTree myCurrentHistoryTree = new DescriptorTree(true);
+
+  private DescriptorTreeSearcher myDescriptorSearcher;
+  private DescriptorTreeSearcher myDisplayDescriptorSearcher;
+
+  protected final Project      myProject;
+
+  public NodeDescriptorFactoryImpl(Project project) {
+    myProject = project;
+    myDescriptorSearcher = new DescriptorTreeSearcher(new MarkedDescriptorTree());
+    myDisplayDescriptorSearcher = new DisplayDescriptorTreeSearcher(new MarkedDescriptorTree());
+  }
+
+  public void dispose() {
+    myCurrentHistoryTree.clear();
+    myDescriptorSearcher.clear();
+    myDisplayDescriptorSearcher.clear();
+  }
+
+  private <T extends NodeDescriptor> T getDescriptor(NodeDescriptor parent, DescriptorData<T> key) {
+    final T descriptor = key.createDescriptor(myProject);
+
+    final T oldDescriptor = findDescriptor(parent, descriptor, key);
+
+    if(oldDescriptor != null && oldDescriptor.getClass() == descriptor.getClass()) {
+      descriptor.setAncestor(oldDescriptor);
+    }
+    else {
+      T displayDescriptor = findDisplayDescriptor(parent, descriptor, key.getDisplayKey());
+      if(displayDescriptor != null) {
+        descriptor.displayAs(displayDescriptor);
+      }
+    }
+
+    myCurrentHistoryTree.addChild(parent, descriptor);
+
+    return descriptor;
+  }
+
+  @Nullable
+  protected <T extends NodeDescriptor>T findDisplayDescriptor(NodeDescriptor parent, T descriptor, DisplayKey<T> key) {
+    return myDisplayDescriptorSearcher.search(parent, descriptor, key);
+  }
+
+  @Nullable
+  protected <T extends NodeDescriptor> T findDescriptor(NodeDescriptor parent, T descriptor, DescriptorData<T> key) {
+    return myDescriptorSearcher.search(parent, descriptor, key);
+  }
+
+  public DescriptorTree getCurrentHistoryTree() {
+    return myCurrentHistoryTree;
+  }
+
+  public void deriveHistoryTree(DescriptorTree tree, final StackFrameContext context) {
+
+    final MarkedDescriptorTree descriptorTree = new MarkedDescriptorTree();
+    final MarkedDescriptorTree displayDescriptorTree = new MarkedDescriptorTree();
+
+    tree.dfst(new DescriptorTree.DFSTWalker() {
+      public void visit(NodeDescriptor parent, NodeDescriptor child) {
+        final DescriptorData<NodeDescriptor> descriptorData = DescriptorData.getDescriptorData(child);
+        descriptorTree.addChild(parent, child, descriptorData);
+        displayDescriptorTree.addChild(parent, child, descriptorData.getDisplayKey());
+      }
+    });
+
+    myDescriptorSearcher = new DescriptorTreeSearcher(descriptorTree);
+    myDisplayDescriptorSearcher = new DisplayDescriptorTreeSearcher(displayDescriptorTree);
+
+    myCurrentHistoryTree = createDescriptorTree(context, tree);
+  }
+
+  private static DescriptorTree createDescriptorTree(final StackFrameContext context, final DescriptorTree fromTree) {
+    int frameCount = -1;
+    int frameIndex = -1;
+    final StackFrameProxy frameProxy = context.getFrameProxy();
+    if (frameProxy != null) {
+      try {
+        final ThreadReferenceProxy threadReferenceProxy = frameProxy.threadProxy();
+        frameCount = threadReferenceProxy.frameCount();
+        frameIndex = frameProxy.getFrameIndex();
+       }
+       catch (EvaluateException e) {
+         // ignored
+       }
+    }
+    final boolean isInitial = !fromTree.frameIdEquals(frameCount, frameIndex);
+    DescriptorTree descriptorTree = new DescriptorTree(isInitial);
+    descriptorTree.setFrameId(frameCount, frameIndex);
+    return descriptorTree;
+  }
+
+  public ArrayElementDescriptorImpl getArrayItemDescriptor(NodeDescriptor parent, ArrayReference array, int index) {
+    return getDescriptor(parent, new ArrayItemData(array, index));
+  }
+
+  public FieldDescriptorImpl getFieldDescriptor(NodeDescriptor parent, ObjectReference objRef, Field field) {
+    final DescriptorData<FieldDescriptorImpl> descriptorData;
+    if (objRef == null ) {
+      if (!field.isStatic()) {
+        LOG.error("Object reference is null for non-static field: " + field);
+      }
+      descriptorData = new StaticFieldData(field);
+    }
+    else {
+      descriptorData = new FieldData(objRef, field);
+    }
+    return getDescriptor(parent, descriptorData);
+  }
+
+  public LocalVariableDescriptorImpl getLocalVariableDescriptor(NodeDescriptor parent, LocalVariableProxy local) {
+    return getDescriptor(parent, new LocalData((LocalVariableProxyImpl)local));
+  }
+
+  public ArgumentValueDescriptorImpl getArgumentValueDescriptor(NodeDescriptor parent, int index, Value value) {
+    return getDescriptor(parent, new ArgValueData(index, value));
+  }
+
+  public StackFrameDescriptorImpl getStackFrameDescriptor(NodeDescriptorImpl parent, StackFrameProxyImpl frameProxy) {
+    return getDescriptor(parent, new StackFrameData(frameProxy));
+  }
+
+  public StaticDescriptorImpl getStaticDescriptor(NodeDescriptorImpl parent, ReferenceType refType) {//static is unique
+    return getDescriptor(parent, new StaticData(refType));
+  }
+
+  public ValueDescriptorImpl getThisDescriptor(NodeDescriptorImpl parent, Value value) {
+    return getDescriptor(parent, new ThisData());
+  }
+
+  public ValueDescriptorImpl getMethodReturnValueDescriptor(NodeDescriptorImpl parent, Method method, Value value) {
+    return getDescriptor(parent, new MethodReturnValueData(method, value));
+  }
+
+  public ThreadDescriptorImpl getThreadDescriptor(NodeDescriptorImpl parent, ThreadReferenceProxyImpl thread) {
+    return getDescriptor(parent, new ThreadData(thread));
+  }
+
+  public ThreadGroupDescriptorImpl getThreadGroupDescriptor(NodeDescriptorImpl parent, ThreadGroupReferenceProxyImpl group) {
+    return getDescriptor(parent, new ThreadGroupData(group));
+  }
+
+  public UserExpressionDescriptor getUserExpressionDescriptor(NodeDescriptor parent, final DescriptorData<UserExpressionDescriptor> data) {
+    return getDescriptor(parent, data);
+  }
+
+  public WatchItemDescriptor getWatchItemDescriptor(NodeDescriptor parent, TextWithImports text, @Nullable Value value){
+    return getDescriptor(parent, new WatchItemData(text, value));
+  }
+  
+  private static class DescriptorTreeSearcher {
+    private final MarkedDescriptorTree myDescriportTree;
+
+    private final HashMap<NodeDescriptor, NodeDescriptor> mySearchedDescriptors = new HashMap<NodeDescriptor, NodeDescriptor>();
+
+    public DescriptorTreeSearcher(MarkedDescriptorTree descriportTree) {
+      myDescriportTree = descriportTree;
+    }
+
+    @Nullable
+    public <T extends NodeDescriptor> T search(NodeDescriptor parent, T descriptor, DescriptorKey<T> key) {
+      final T result;
+      if(parent == null) {
+        result = myDescriportTree.getChild(null, key);
+      }
+      else {
+        final NodeDescriptor parentDescriptor = getSearched(parent);
+        result = parentDescriptor != null ? myDescriportTree.getChild(parentDescriptor, key) : null;
+      }
+      if(result != null) {
+        mySearchedDescriptors.put(descriptor, result);
+      }
+      return result;
+    }
+
+    protected NodeDescriptor getSearched(NodeDescriptor parent) {
+      return mySearchedDescriptors.get(parent);
+    }
+
+    public void clear() {
+      mySearchedDescriptors.clear();
+      myDescriportTree.clear();
+    }
+  }
+
+  private class DisplayDescriptorTreeSearcher extends DescriptorTreeSearcher {
+    public DisplayDescriptorTreeSearcher(MarkedDescriptorTree descriportTree) {
+      super(descriportTree);
+    }
+
+    protected NodeDescriptor getSearched(NodeDescriptor parent) {
+      NodeDescriptor searched = super.getSearched(parent);
+      if(searched == null) {
+        return myDescriptorSearcher.getSearched(parent);
+      }
+      return searched;
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeDescriptorImpl.java
new file mode 100644
index 0000000..a009733
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeDescriptorImpl.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.impl.watch;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.DebugProcess;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.ui.tree.NodeDescriptor;
+import com.intellij.debugger.ui.tree.render.DescriptorLabelListener;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.Key;
+import com.intellij.util.containers.HashMap;
+import com.intellij.xdebugger.impl.ui.tree.ValueMarkup;
+import com.sun.jdi.InconsistentDebugInfoException;
+import com.sun.jdi.InvalidStackFrameException;
+import com.sun.jdi.ObjectReference;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public abstract class NodeDescriptorImpl implements NodeDescriptor {
+  protected static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl");
+
+  public static final String UNKNOWN_VALUE_MESSAGE = "";
+  public boolean myIsExpanded = false;
+  public boolean myIsSelected = false;
+  public boolean myIsVisible  = false;
+  public boolean myIsSynthetic = false;
+
+  private EvaluateException myEvaluateException;
+  private String myLabel = UNKNOWN_VALUE_MESSAGE;
+
+  private HashMap<Key, Object> myUserData;
+
+  private final List<NodeDescriptorImpl> myChildren = new ArrayList<NodeDescriptorImpl>();
+  private static final Key<Map<ObjectReference, ValueMarkup>> MARKUP_MAP_KEY = new Key<Map<ObjectReference, ValueMarkup>>("ValueMarkupMap");
+
+  public String getName() {
+    return null;
+  }
+
+  public <T> T getUserData(Key<T> key) {
+    if(myUserData == null) return null;
+    return (T) myUserData.get(key);
+  }
+
+  public <T> void putUserData(Key<T> key, T value) {
+    if(myUserData == null) {
+      myUserData = new HashMap<Key, Object>();
+    }
+    myUserData.put(key, value);
+  }
+
+  public void updateRepresentation(EvaluationContextImpl context, DescriptorLabelListener labelListener){
+    updateRepresentationNoNotify(context, labelListener);
+    labelListener.labelChanged();
+  }
+
+  protected void updateRepresentationNoNotify(EvaluationContextImpl context, DescriptorLabelListener labelListener) {
+    try {
+      try {
+        myEvaluateException = null;
+        myLabel = calcRepresentation(context, labelListener);
+      }
+      catch (RuntimeException e) {
+        LOG.debug(e);
+        throw processException(e);
+      }
+    }
+    catch (EvaluateException e) {
+      setFailed(e);
+    }
+  }
+
+  protected abstract String calcRepresentation(EvaluationContextImpl context, DescriptorLabelListener labelListener) throws EvaluateException;
+
+  private EvaluateException processException(Exception e) {
+    if(e instanceof InconsistentDebugInfoException) {
+      return new EvaluateException(DebuggerBundle.message("error.inconsistent.debug.info"), null);
+    }
+
+    else if(e instanceof InvalidStackFrameException) {
+      return new EvaluateException(DebuggerBundle.message("error.invalid.stackframe"), null);
+    }
+    else {
+      return EvaluateExceptionUtil.DEBUG_INFO_UNAVAILABLE;
+    }
+  }
+
+  public void displayAs(NodeDescriptor descriptor) {
+    if (descriptor instanceof NodeDescriptorImpl) {
+      final NodeDescriptorImpl that = (NodeDescriptorImpl)descriptor;
+      myIsExpanded = that.myIsExpanded;
+      myIsSelected = that.myIsSelected;
+      myIsVisible  = that.myIsVisible;
+      myUserData = that.myUserData != null ? new HashMap<Key, Object>(that.myUserData) : null;
+    }
+  }
+
+  public abstract boolean isExpandable();
+
+  public abstract void setContext(EvaluationContextImpl context);
+
+  public EvaluateException getEvaluateException() {
+    return myEvaluateException;
+  }
+
+  public String getLabel() {
+    return myLabel;
+  }
+
+  public String toString() {
+    return getLabel();
+  }
+
+  protected String setFailed(EvaluateException e) {
+    myEvaluateException = e;
+    return e.getMessage();
+  }
+
+  protected String setLabel(String customLabel) {
+    return myLabel = customLabel;
+  }
+
+  //Context is set to null
+  public void clear() {
+    myEvaluateException = null;
+    myLabel = "";
+  }
+
+  public List<NodeDescriptorImpl> getChildren() {
+    return myChildren;
+  }
+
+  public void setAncestor(NodeDescriptor oldDescriptor) {
+    displayAs(oldDescriptor);
+  }
+
+  @Nullable
+  public static Map<ObjectReference, ValueMarkup> getMarkupMap(final DebugProcess process) {
+    if (process == null) {
+      return null;
+    }
+    Map<ObjectReference, ValueMarkup> map = process.getUserData(MARKUP_MAP_KEY);
+    if (map == null) {
+      map = new java.util.HashMap<ObjectReference, ValueMarkup>();
+      process.putUserData(MARKUP_MAP_KEY, map);
+    }
+    return map;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeManagerImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeManagerImpl.java
new file mode 100644
index 0000000..905f7b0
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeManagerImpl.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.impl.watch;
+
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContext;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.jdi.StackFrameProxyImpl;
+import com.intellij.debugger.ui.impl.nodes.NodeComparator;
+import com.intellij.debugger.ui.tree.DebuggerTreeNode;
+import com.intellij.debugger.ui.tree.NodeDescriptor;
+import com.intellij.debugger.ui.tree.NodeManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.util.StringBuilderSpinAllocator;
+import com.intellij.util.containers.HashMap;
+import com.sun.jdi.Location;
+import com.sun.jdi.Method;
+import com.sun.jdi.ReferenceType;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Comparator;
+import java.util.Map;
+
+/**
+ ** finds correspondence between new descriptor and one created on the previous steps
+ ** stores maximum  CACHED_STEPS steps
+ ** call saveState function to start new step
+ */
+
+public class NodeManagerImpl extends NodeDescriptorFactoryImpl implements NodeManager{
+  private static final Comparator<DebuggerTreeNode> ourNodeComparator = new NodeComparator();
+
+  private final DebuggerTree myDebuggerTree;
+  private String myHistoryKey = null;
+  private final Map<String, DescriptorTree> myHistories = new HashMap<String, DescriptorTree>();
+
+  public NodeManagerImpl(Project project, DebuggerTree tree) {
+    super(project);
+    myDebuggerTree = tree;
+  }
+
+  public static Comparator<DebuggerTreeNode> getNodeComparator() {
+    return ourNodeComparator;
+  }
+
+  public DebuggerTreeNodeImpl createNode(NodeDescriptor descriptor, EvaluationContext evaluationContext) {
+    ((NodeDescriptorImpl)descriptor).setContext((EvaluationContextImpl)evaluationContext);
+    return DebuggerTreeNodeImpl.createNode(getTree(), (NodeDescriptorImpl)descriptor, (EvaluationContextImpl)evaluationContext);
+  }
+
+  public DebuggerTreeNodeImpl getDefaultNode() {
+    return DebuggerTreeNodeImpl.createNodeNoUpdate(getTree(), new DefaultNodeDescriptor());
+  }
+
+  public DebuggerTreeNodeImpl createMessageNode(MessageDescriptor descriptor) {
+    return DebuggerTreeNodeImpl.createNodeNoUpdate(getTree(), descriptor);
+  }
+
+  public DebuggerTreeNodeImpl createMessageNode(String message) {
+    return DebuggerTreeNodeImpl.createNodeNoUpdate(getTree(), new MessageDescriptor(message));
+  }
+
+  public void setHistoryByContext(final DebuggerContextImpl context) {
+    if (myHistoryKey != null) {
+      myHistories.put(myHistoryKey, getCurrentHistoryTree());
+    }
+
+    final String historyKey = getContextKey(context.getFrameProxy());
+    final DescriptorTree descriptorTree;
+    if (historyKey != null) {
+      final DescriptorTree historyTree = myHistories.get(historyKey);
+      descriptorTree = (historyTree != null)? historyTree : new DescriptorTree(true);
+    }
+    else {
+      descriptorTree = new DescriptorTree(true);
+    }
+
+    deriveHistoryTree(descriptorTree, context);
+    myHistoryKey = historyKey;
+  }
+
+
+  @Nullable
+  public String getContextKey(final StackFrameProxyImpl frame) {
+    return getContextKeyForFrame(frame);
+  }
+
+  @Nullable
+  public static String getContextKeyForFrame(final StackFrameProxyImpl frame) {
+    if (frame == null) {
+      return null;
+    }
+    try {
+      final Location location = frame.location();
+      final Method method = location.method();
+      final ReferenceType referenceType = location.declaringType();
+      final StringBuilder builder = StringBuilderSpinAllocator.alloc();
+      try {
+        return builder.append(referenceType.signature()).append("#").append(method.name()).append(method.signature()).toString();
+      }
+      finally {
+        StringBuilderSpinAllocator.dispose(builder);
+      }
+    }
+    catch (EvaluateException e) {
+      return null;
+    }
+  }
+
+  public void dispose() {
+    myHistories.clear();
+    super.dispose();
+  }
+
+  private DebuggerTree getTree() {
+    return myDebuggerTree;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/StackFrameDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/StackFrameDescriptorImpl.java
new file mode 100644
index 0000000..41a5384
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/StackFrameDescriptorImpl.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.impl.watch;
+
+import com.intellij.debugger.SourcePosition;
+import com.intellij.debugger.engine.ContextUtil;
+import com.intellij.debugger.engine.DebugProcess;
+import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
+import com.intellij.debugger.engine.DebuggerUtils;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.jdi.StackFrameProxyImpl;
+import com.intellij.debugger.settings.ThreadsViewSettings;
+import com.intellij.debugger.ui.tree.StackFrameDescriptor;
+import com.intellij.debugger.ui.tree.render.DescriptorLabelListener;
+import com.intellij.icons.AllIcons;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.roots.ProjectFileIndex;
+import com.intellij.openapi.roots.ProjectRootManager;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiFile;
+import com.intellij.ui.FileColorManager;
+import com.intellij.util.StringBuilderSpinAllocator;
+import com.intellij.xdebugger.impl.ui.tree.ValueMarkup;
+import com.sun.jdi.*;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.awt.*;
+import java.util.Map;
+
+/**
+ * Nodes of this type cannot be updated, because StackFrame objects become invalid as soon as VM has been resumed
+ */
+public class StackFrameDescriptorImpl extends NodeDescriptorImpl implements StackFrameDescriptor{
+  private final StackFrameProxyImpl myFrame;
+  private int myUiIndex;
+  private String myName = null;
+  private Location myLocation;
+  private MethodsTracker.MethodOccurrence myMethodOccurrence;
+  private boolean myIsSynthetic;
+  private boolean myIsInLibraryContent;
+  private ObjectReference myThisObject;
+  private Color myBackgroundColor;
+
+  private Icon myIcon = AllIcons.Debugger.StackFrame;
+
+  public StackFrameDescriptorImpl(StackFrameProxyImpl frame, final MethodsTracker tracker) {
+    myFrame = frame;
+    try {
+      myUiIndex = frame.getFrameIndex();
+      myLocation = frame.location();
+      myThisObject = frame.thisObject();
+      myMethodOccurrence = tracker.getMethodOccurrence(myLocation.method());
+      myIsSynthetic = DebuggerUtils.isSynthetic(myMethodOccurrence.getMethod());
+      ApplicationManager.getApplication().runReadAction(new Runnable() {
+        public void run() {
+          final SourcePosition position = ContextUtil.getSourcePosition(StackFrameDescriptorImpl.this);
+          final PsiFile file = position != null? position.getFile() : null;
+          if (file == null) {
+            myIsInLibraryContent = true;
+          }
+          else {
+            myBackgroundColor = FileColorManager.getInstance(file.getProject()).getFileColor(file);
+            
+            final ProjectFileIndex projectFileIndex = ProjectRootManager.getInstance(getDebugProcess().getProject()).getFileIndex();
+            final VirtualFile vFile = file.getVirtualFile();
+            myIsInLibraryContent = vFile != null && (projectFileIndex.isInLibraryClasses(vFile) || projectFileIndex.isInLibrarySource(vFile));
+          }
+        }
+      });
+    }
+    catch(InternalException e) {
+      LOG.info(e);
+      myLocation = null;
+      myMethodOccurrence = tracker.getMethodOccurrence(null);
+      myIsSynthetic = false;
+      myIsInLibraryContent = false;
+    }
+    catch (EvaluateException e) {
+      LOG.info(e);
+      myLocation = null;
+      myMethodOccurrence = tracker.getMethodOccurrence(null);
+      myIsSynthetic = false;
+      myIsInLibraryContent = false;
+    }
+  }
+
+  public int getUiIndex() {
+    return myUiIndex;
+  }
+
+  public StackFrameProxyImpl getFrameProxy() {
+    return myFrame;
+  }
+
+  public DebugProcess getDebugProcess() {
+    return myFrame.getVirtualMachine().getDebugProcess();
+  }
+
+  @Override
+  public Color getBackgroundColor() {
+    return myBackgroundColor;
+  }
+
+  @Nullable
+  public Method getMethod() {
+    return myMethodOccurrence.getMethod();
+  }
+
+  public int getOccurrenceIndex() {
+    return myMethodOccurrence.getIndex();
+  }
+
+  public boolean isRecursiveCall() {
+    return myMethodOccurrence.isRecursive();
+  }
+
+  @Nullable
+  public ValueMarkup getValueMarkup() {
+    if (myThisObject != null) {
+      final Map<ObjectReference, ValueMarkup> markupMap = getMarkupMap(myFrame.getVirtualMachine().getDebugProcess());
+      if (markupMap != null) {
+        return markupMap.get(myThisObject);
+      }
+    }
+    return null;
+  }
+  
+  public String getName() {
+    return myName;
+  }
+
+  protected String calcRepresentation(EvaluationContextImpl context, DescriptorLabelListener descriptorLabelListener) throws EvaluateException {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    if (myLocation == null) {
+      return "";
+    }
+    ThreadsViewSettings settings = ThreadsViewSettings.getInstance();
+    final StringBuilder label = StringBuilderSpinAllocator.alloc();
+    try {
+      Method method = myMethodOccurrence.getMethod();
+      if (method != null) {
+        myName = method.name();
+        label.append(myName);
+        label.append("()");
+      }
+      if (settings.SHOW_LINE_NUMBER) {
+        String lineNumber = null;
+        try {
+          lineNumber = Integer.toString(myLocation.lineNumber());
+        }
+        catch (InternalError e) {
+          lineNumber = e.toString();
+        }
+        if (lineNumber != null) {
+          label.append(':');
+          label.append(lineNumber);
+        }
+      }
+      if (settings.SHOW_CLASS_NAME) {
+        String name = null;
+        try {
+          ReferenceType refType = myLocation.declaringType();
+          name = refType != null ? refType.name() : null;
+        }
+        catch (InternalError e) {
+          name = e.toString();
+        }
+        if (name != null) {
+          label.append(", ");
+          int dotIndex = name.lastIndexOf('.');
+          if (dotIndex < 0) {
+            label.append(name);
+          }
+          else {
+            label.append(name.substring(dotIndex + 1));
+            label.append(" {");
+            label.append(name.substring(0, dotIndex));
+            label.append("}");
+          }
+        }
+      }
+      if (settings.SHOW_SOURCE_NAME) {
+        try {
+          String sourceName;
+          try {
+            sourceName = myLocation.sourceName();
+          }
+          catch (InternalError e) {
+            sourceName = e.toString();
+          }
+          label.append(", ");
+          label.append(sourceName);
+        }
+        catch (AbsentInformationException exception) {
+        }
+      }
+      return label.toString();
+    }
+    finally {
+      StringBuilderSpinAllocator.dispose(label);
+    }
+  }
+
+  public final boolean stackFramesEqual(StackFrameDescriptorImpl d) {
+    return getFrameProxy().equals(d.getFrameProxy());
+  }
+
+  public boolean isExpandable() {
+    return true;
+  }
+
+  public final void setContext(EvaluationContextImpl context) {
+    myIcon = calcIcon();
+  }
+
+  public boolean isSynthetic() {
+    return myIsSynthetic;
+  }
+
+  public boolean isInLibraryContent() {
+    return myIsInLibraryContent;
+  }
+
+  public Location getLocation() {
+    return myLocation;
+  }
+
+  private Icon calcIcon() {
+    try {
+      if(myFrame.isObsolete()) {
+        return AllIcons.Debugger.Db_obsolete;
+      }
+    }
+    catch (EvaluateException e) {
+    }
+    return AllIcons.Debugger.StackFrame;
+  }
+
+  public Icon getIcon() {
+    return myIcon;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/StaticDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/StaticDescriptorImpl.java
new file mode 100644
index 0000000..6284de4
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/StaticDescriptorImpl.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class StaticDescriptorImpl
+ * @author Jeka
+ */
+package com.intellij.debugger.ui.impl.watch;
+
+import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.settings.NodeRendererSettings;
+import com.intellij.debugger.ui.tree.StaticDescriptor;
+import com.intellij.debugger.ui.tree.render.ClassRenderer;
+import com.intellij.debugger.ui.tree.render.DescriptorLabelListener;
+import com.sun.jdi.Field;
+import com.sun.jdi.ReferenceType;
+
+public class StaticDescriptorImpl extends NodeDescriptorImpl implements StaticDescriptor{
+
+  private final ReferenceType myType;
+  private final boolean myHasStaticFields;
+
+  public StaticDescriptorImpl(ReferenceType refType) {
+    myType = refType;
+
+    boolean hasStaticFields = false;
+    for (Field field : myType.allFields()) {
+      if (field.isStatic()) {
+        hasStaticFields = true;
+        break;
+      }
+    }
+    myHasStaticFields = hasStaticFields;
+  }
+
+  public ReferenceType getType() {
+    return myType;
+  }
+
+  public String getName() {
+    //noinspection HardCodedStringLiteral
+    return "static";
+  }
+
+  public boolean isExpandable() {
+    return myHasStaticFields;
+  }
+
+  public void setContext(EvaluationContextImpl context) {
+  }
+
+  protected String calcRepresentation(EvaluationContextImpl context, DescriptorLabelListener descriptorLabelListener) throws EvaluateException {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    final ClassRenderer classRenderer = NodeRendererSettings.getInstance().getClassRenderer();
+    return getName() + " = " + classRenderer.renderTypeName(myType.name());
+  }
+}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ThisDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ThisDescriptorImpl.java
new file mode 100644
index 0000000..67e8304
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ThisDescriptorImpl.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.impl.watch;
+
+import com.intellij.debugger.DebuggerContext;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.JavaPsiFacade;
+import com.intellij.psi.PsiElementFactory;
+import com.intellij.psi.PsiExpression;
+import com.intellij.util.IncorrectOperationException;
+import com.sun.jdi.Value;
+
+/**
+ * User: lex
+ * Date: Oct 8, 2003
+ * Time: 5:08:07 PM
+ */
+public class ThisDescriptorImpl extends ValueDescriptorImpl{
+
+  public ThisDescriptorImpl(Project project) {
+    super(project);
+  }
+
+  public Value calcValue(EvaluationContextImpl evaluationContext) throws EvaluateException {
+    return evaluationContext != null? evaluationContext.getThisObject() : null;
+  }
+
+  public String getName() {
+    //noinspection HardCodedStringLiteral
+    return "this"; 
+  }
+
+  public String calcValueName() {
+    return getName();
+  }
+
+  public PsiExpression getDescriptorEvaluation(DebuggerContext context) throws EvaluateException {
+    PsiElementFactory elementFactory = JavaPsiFacade.getInstance(context.getProject()).getElementFactory();
+    try {
+      return elementFactory.createExpressionFromText("this", null);
+    }
+    catch (IncorrectOperationException e) {
+      throw new EvaluateException(e.getMessage(), e);
+    }
+  }
+
+  public boolean canSetValue() {
+    return false;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ThreadDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ThreadDescriptorImpl.java
new file mode 100644
index 0000000..dd50562
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ThreadDescriptorImpl.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.impl.watch;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
+import com.intellij.debugger.engine.SuspendContextImpl;
+import com.intellij.debugger.engine.SuspendManager;
+import com.intellij.debugger.engine.SuspendManagerUtil;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.jdi.ThreadGroupReferenceProxyImpl;
+import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
+import com.intellij.debugger.ui.tree.ThreadDescriptor;
+import com.intellij.debugger.ui.tree.render.DescriptorLabelListener;
+import com.intellij.icons.AllIcons;
+import com.sun.jdi.ObjectCollectedException;
+import com.sun.jdi.ThreadReference;
+
+import javax.swing.*;
+
+public class ThreadDescriptorImpl extends NodeDescriptorImpl implements ThreadDescriptor{
+  private final ThreadReferenceProxyImpl myThread;
+  private String myName = null;
+  private boolean myIsExpandable   = true;
+  private boolean myIsSuspended    = false;
+  private boolean myIsCurrent;
+  private boolean myIsFrozen;
+
+  private boolean            myIsAtBreakpoint;
+  private SuspendContextImpl mySuspendContext;
+
+  public ThreadDescriptorImpl(ThreadReferenceProxyImpl thread) {
+    myThread = thread;
+  }
+
+  public String getName() {
+    return myName;
+  }
+
+  protected String calcRepresentation(EvaluationContextImpl context, DescriptorLabelListener labelListener) throws EvaluateException {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    ThreadReferenceProxyImpl thread = getThreadReference();
+    try {
+      myName = thread.name();
+      ThreadGroupReferenceProxyImpl gr = getThreadReference().threadGroupProxy();
+      final String grname = (gr != null)? gr.name() : null;
+      final String threadStatusText = DebuggerUtilsEx.getThreadStatusText(getThreadReference().status());
+      //noinspection HardCodedStringLiteral
+      if (grname != null && !"SYSTEM".equalsIgnoreCase(grname)) {
+        return DebuggerBundle.message("label.thread.node.in.group", myName, thread.uniqueID(), threadStatusText, grname);
+      }
+      return DebuggerBundle.message("label.thread.node", myName, thread.uniqueID(), threadStatusText);
+    }
+    catch (ObjectCollectedException e) {
+      return myName != null ? DebuggerBundle.message("label.thread.node.thread.collected", myName) : "";
+    }
+  }
+
+  public ThreadReferenceProxyImpl getThreadReference() {
+    return myThread;
+  }
+
+  public boolean isCurrent() {
+    return myIsCurrent;
+  }
+
+  public boolean isFrozen() {
+    return myIsFrozen;
+  }
+
+  public boolean isExpandable() {
+    return myIsExpandable;
+  }
+
+  public void setContext(EvaluationContextImpl context) {
+    final ThreadReferenceProxyImpl thread = getThreadReference();
+    final SuspendManager suspendManager = context != null? context.getDebugProcess().getSuspendManager() : null;
+    final SuspendContextImpl suspendContext = context != null? context.getSuspendContext() : null;
+
+    try {
+      myIsSuspended = suspendManager != null? suspendManager.isSuspended(thread) : thread.isSuspended();
+    }
+    catch (ObjectCollectedException e) {
+      myIsSuspended = false;
+    }
+    myIsExpandable   = calcExpandable(myIsSuspended);
+    mySuspendContext = SuspendManagerUtil.getSuspendContextForThread(suspendContext, thread);
+    myIsAtBreakpoint = suspendManager != null? SuspendManagerUtil.findContextByThread(suspendManager, thread) != null : thread.getThreadReference().isAtBreakpoint();
+    myIsCurrent      = suspendContext != null? suspendContext.getThread() == thread : false;
+    myIsFrozen       = suspendManager != null? suspendManager.isFrozen(thread) : myIsSuspended;
+  }
+
+  private boolean calcExpandable(final boolean isSuspended) {
+    if (!isSuspended) {
+      return false;
+    }
+    final int status = getThreadReference().status();
+    if (status == ThreadReference.THREAD_STATUS_UNKNOWN ||
+        status == ThreadReference.THREAD_STATUS_NOT_STARTED ||
+        status == ThreadReference.THREAD_STATUS_ZOMBIE) {
+      return false;
+    }
+    return true;
+    /*
+    // [jeka] with lots of threads calling threadProxy.frameCount() in advance while setting context can be costly....
+    // see IDEADEV-2020
+    try {
+      return threadProxy.frameCount() > 0;
+    }
+    catch (EvaluateException e) {
+      //LOG.assertTrue(false);
+      // if we pause during evaluation of this method the exception is thrown
+      //  private static void longMethod(){
+      //    try {
+      //      Thread.sleep(100000);
+      //    } catch (InterruptedException e) {
+      //      e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
+      //    }
+      //  }
+      return false;
+    }
+    */
+  }
+
+  public SuspendContextImpl getSuspendContext() {
+    return mySuspendContext;
+  }
+
+  public boolean isAtBreakpoint() {
+    return myIsAtBreakpoint;
+  }
+
+  public boolean isSuspended() {
+    return myIsSuspended;
+  }
+
+  public Icon getIcon() {
+    if(isCurrent()) {
+      return AllIcons.Debugger.ThreadCurrent;
+    }
+    if(isFrozen()) {
+      return AllIcons.Debugger.ThreadFrozen;
+    }
+    if(isAtBreakpoint()) {
+      return AllIcons.Debugger.ThreadAtBreakpoint;
+    }
+    if(isSuspended()) {
+      return AllIcons.Debugger.ThreadSuspended;
+    }
+    return AllIcons.Debugger.ThreadRunning;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ThreadGroupDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ThreadGroupDescriptorImpl.java
new file mode 100644
index 0000000..2f0b304
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ThreadGroupDescriptorImpl.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.impl.watch;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.jdi.ThreadGroupReferenceProxyImpl;
+import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
+import com.intellij.debugger.ui.tree.ThreadGroupDescriptor;
+import com.intellij.debugger.ui.tree.render.DescriptorLabelListener;
+import com.sun.jdi.ObjectCollectedException;
+
+public class ThreadGroupDescriptorImpl extends NodeDescriptorImpl implements ThreadGroupDescriptor{
+  private final ThreadGroupReferenceProxyImpl myThreadGroup;
+  private boolean myIsCurrent;
+  private String myName = null;
+  private boolean myIsExpandable = true;
+
+  public ThreadGroupDescriptorImpl(ThreadGroupReferenceProxyImpl threadGroup) {
+    myThreadGroup = threadGroup;
+  }
+
+  public ThreadGroupReferenceProxyImpl getThreadGroupReference() {
+    return myThreadGroup;
+  }
+
+  public boolean isCurrent() {
+    return myIsCurrent;
+  }
+
+  public String getName() {
+    return myName;
+  }
+
+  protected String calcRepresentation(EvaluationContextImpl context, DescriptorLabelListener labelListener) throws EvaluateException {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    ThreadGroupReferenceProxyImpl group = getThreadGroupReference();
+    try {
+      myName = group.name();
+      return DebuggerBundle.message("label.thread.group.node", myName, group.uniqueID());
+    }
+    catch (ObjectCollectedException e) {
+      return myName != null ? DebuggerBundle.message("label.thread.group.node.group.collected", myName) : "";
+    }
+  }
+
+  public boolean isExpandable() {
+    return myIsExpandable;
+  }
+
+  public void setContext(EvaluationContextImpl context) {
+    ThreadReferenceProxyImpl threadProxy = context != null? context.getSuspendContext().getThread() : null;
+    myIsCurrent = threadProxy != null && isDescendantGroup(threadProxy.threadGroupProxy());
+    myIsExpandable = calcExpandable();
+  }
+
+  private boolean isDescendantGroup(ThreadGroupReferenceProxyImpl group) {
+    if(group == null) return false;
+
+    if(getThreadGroupReference() == group) return true;
+
+    return isDescendantGroup(group.parent());
+  }
+
+  private boolean calcExpandable() {
+    ThreadGroupReferenceProxyImpl group = getThreadGroupReference();
+    return group.threads().size() > 0 || group.threadGroups().size() > 0;
+  }
+}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/UserExpressionDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/UserExpressionDescriptorImpl.java
new file mode 100644
index 0000000..c3dbed6
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/UserExpressionDescriptorImpl.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class StaticDescriptorImpl
+ * @author Jeka
+ */
+package com.intellij.debugger.ui.impl.watch;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.StackFrameContext;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.settings.NodeRendererSettings;
+import com.intellij.debugger.ui.tree.UserExpressionDescriptor;
+import com.intellij.debugger.ui.tree.render.ClassRenderer;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiCodeFragment;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.util.StringBuilderSpinAllocator;
+import com.sun.jdi.ObjectReference;
+import com.sun.jdi.Value;
+
+public class UserExpressionDescriptorImpl extends EvaluationDescriptor implements UserExpressionDescriptor{
+  private final ValueDescriptorImpl myParentDescriptor;
+  private final String myTypeName;
+  private final String myName;
+
+  public UserExpressionDescriptorImpl(Project project, ValueDescriptorImpl parent, String typeName, String name, TextWithImports text) {
+    super(text, project);
+    myParentDescriptor = parent;
+    myTypeName = typeName;
+    myName = name;
+  }
+
+  public String getName() {
+    return myName;
+  }
+
+  public String calcValueName() {
+    StringBuilder buffer = StringBuilderSpinAllocator.alloc();
+    try {
+      buffer.append(getName());
+      buffer.append(": ");
+      final Value value = getValue();
+      if(value != null) {
+        final ClassRenderer classRenderer = NodeRendererSettings.getInstance().getClassRenderer();
+        buffer.append(classRenderer.renderTypeName(value.type().name()));
+      }
+
+      return buffer.toString();
+    }
+    finally {
+      StringBuilderSpinAllocator.dispose(buffer);
+    }
+  }
+
+  protected PsiCodeFragment getEvaluationCode(final StackFrameContext context) throws EvaluateException {
+    Value value = myParentDescriptor.getValue();
+
+    if(value instanceof ObjectReference) {
+      final String typeName = value.type().name();
+
+      final PsiClass psiClass = DebuggerUtilsEx.findClass(myTypeName, myProject, context.getDebugProcess().getSearchScope());
+
+      if (psiClass == null) {
+        throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.invalid.type.name", typeName));
+      }
+
+      final PsiCodeFragment fragment =
+        getEffectiveCodeFragmentFactory(psiClass).createCodeFragment(getEvaluationText(), psiClass, myProject);
+      fragment.forceResolveScope(GlobalSearchScope.allScope(myProject));
+      return fragment;
+    }
+    else {
+      throw EvaluateExceptionUtil.createEvaluateException(
+        DebuggerBundle.message("evaluation.error.objref.expected", myParentDescriptor.getName())
+      );
+    }
+  }
+
+  public ValueDescriptorImpl getParentDescriptor() {
+    return myParentDescriptor;
+  }
+
+  protected EvaluationContextImpl getEvaluationContext(final EvaluationContextImpl evaluationContext) {
+    return evaluationContext.createEvaluationContext(myParentDescriptor.getValue());
+  }
+}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ValueDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ValueDescriptorImpl.java
new file mode 100644
index 0000000..3e11145
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ValueDescriptorImpl.java
@@ -0,0 +1,464 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.impl.watch;
+
+import com.intellij.Patches;
+import com.intellij.debugger.DebuggerContext;
+import com.intellij.debugger.engine.DebugProcess;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
+import com.intellij.debugger.engine.DebuggerUtils;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
+import com.intellij.debugger.settings.NodeRendererSettings;
+import com.intellij.debugger.ui.tree.NodeDescriptor;
+import com.intellij.debugger.ui.tree.ValueDescriptor;
+import com.intellij.debugger.ui.tree.render.ClassRenderer;
+import com.intellij.debugger.ui.tree.render.DescriptorLabelListener;
+import com.intellij.debugger.ui.tree.render.NodeRenderer;
+import com.intellij.debugger.ui.tree.render.Renderer;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiExpression;
+import com.intellij.util.StringBuilderSpinAllocator;
+import com.intellij.util.concurrency.Semaphore;
+import com.intellij.xdebugger.impl.ui.tree.ValueMarkup;
+import com.sun.jdi.*;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+public abstract class ValueDescriptorImpl extends NodeDescriptorImpl implements ValueDescriptor{
+  protected final Project myProject;
+
+  NodeRenderer myRenderer = null;
+
+  NodeRenderer myAutoRenderer = null;
+
+  private Value myValue;
+  private EvaluateException myValueException;
+  protected EvaluationContextImpl myStoredEvaluationContext = null;
+
+  private String myValueLabel;
+  @Nullable
+  private Icon myValueIcon;
+
+  protected boolean myIsNew = true;
+  private boolean myIsDirty = false;
+  private boolean myIsLvalue = false;
+  private boolean myIsExpandable;
+
+  private boolean myShowIdLabel = true;
+
+  protected ValueDescriptorImpl(Project project, Value value) {
+    myProject = project;
+    myValue = value;
+  }
+
+  protected ValueDescriptorImpl(Project project) {
+    myProject = project;
+  }
+
+  public boolean isArray() { 
+    return myValue instanceof ArrayReference; 
+  }
+  
+  public boolean isDirty() { 
+    return myIsDirty; 
+  }
+  
+  public boolean isLvalue() { 
+    return myIsLvalue; 
+  }
+  
+  public boolean isNull() { 
+    return myValue == null; 
+  }
+
+  @Override
+  public boolean isString() {
+    return myValue instanceof StringReference;
+  }
+
+  public boolean isPrimitive() {
+    return myValue instanceof PrimitiveValue; 
+  }
+  
+  public boolean isValueValid() {
+    return myValueException == null;
+  }
+
+  public boolean isShowIdLabel() {
+    return myShowIdLabel;
+  }
+
+  public void setShowIdLabel(boolean showIdLabel) {
+    myShowIdLabel = showIdLabel;
+  }
+
+  public Value getValue() {
+    // the following code makes sense only if we do not use ObjectReference.enableCollection() / disableCollection()
+    // to keep temporary objects
+    if (Patches.IBM_JDK_DISABLE_COLLECTION_BUG && myStoredEvaluationContext != null && !myStoredEvaluationContext.getSuspendContext().isResumed() &&
+        myValue instanceof ObjectReference && VirtualMachineProxyImpl.isCollected((ObjectReference)myValue)) {
+
+      final Semaphore semaphore = new Semaphore();
+      semaphore.down();
+      myStoredEvaluationContext.getDebugProcess().getManagerThread().invoke(new SuspendContextCommandImpl(myStoredEvaluationContext.getSuspendContext()) {
+        public void contextAction() throws Exception {
+          // re-setting the context will cause value recalculation
+          try {
+            setContext(myStoredEvaluationContext);
+          }
+          finally {
+            semaphore.up();
+          }
+        }
+      });
+      semaphore.waitFor();
+    }
+    
+    return myValue; 
+  }
+  
+  public boolean isExpandable() {
+    return myIsExpandable;
+  }
+
+  public abstract Value calcValue(EvaluationContextImpl evaluationContext) throws EvaluateException;
+
+  public final void setContext(EvaluationContextImpl evaluationContext) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    if (Patches.IBM_JDK_DISABLE_COLLECTION_BUG) {
+      myStoredEvaluationContext = evaluationContext;
+    }
+    Value value;
+    try {
+      value = calcValue(evaluationContext);
+
+      if(!myIsNew) {
+        try {
+          if (myValue instanceof DoubleValue && Double.isNaN(((DoubleValue)myValue).doubleValue())) {
+            myIsDirty = !(value instanceof DoubleValue);
+          }
+          else if (myValue instanceof FloatValue && Float.isNaN(((FloatValue)myValue).floatValue())) {
+            myIsDirty = !(value instanceof FloatValue);
+          }
+          else {
+            myIsDirty = (value == null) ? myValue != null : !value.equals(myValue);
+          }
+        }
+        catch (ObjectCollectedException e) {
+          myIsDirty = true;
+        }
+      }
+      myValue = value;
+      myValueException = null;
+    }
+    catch (EvaluateException e) {
+      myValueException = e;
+      myValue = getTargetExceptionWithStackTraceFilled(evaluationContext, e);
+      myIsExpandable = false;
+    }
+
+    myIsNew = false;
+  }
+
+  @Nullable
+  private static ObjectReference getTargetExceptionWithStackTraceFilled(final EvaluationContextImpl evaluationContext, EvaluateException ex){
+    final ObjectReference exceptionObj = ex.getExceptionFromTargetVM();
+    if (exceptionObj != null && evaluationContext != null) {
+      try {
+        final ReferenceType refType = exceptionObj.referenceType();
+        final List<Method> methods = refType.methodsByName("getStackTrace", "()[Ljava/lang/StackTraceElement;");
+        if (methods.size() > 0) {
+          final DebugProcessImpl process = evaluationContext.getDebugProcess();
+          process.invokeMethod(evaluationContext, exceptionObj, methods.get(0), Collections.emptyList());
+          
+          // print to console as well
+          
+          final Field traceField = refType.fieldByName("stackTrace");
+          final Value trace = traceField != null? exceptionObj.getValue(traceField) : null; 
+          if (trace instanceof ArrayReference) {
+            final ArrayReference traceArray = (ArrayReference)trace;
+            final Type componentType = ((ArrayType)traceArray.referenceType()).componentType();
+            if (componentType instanceof ClassType) {
+              process.printToConsole(DebuggerUtils.getValueAsString(evaluationContext, exceptionObj));
+              process.printToConsole("\n");
+              for (Value stackElement : traceArray.getValues()) {
+                process.printToConsole("\tat ");
+                process.printToConsole(DebuggerUtils.getValueAsString(evaluationContext, stackElement));
+                process.printToConsole("\n");
+              }
+            }
+          }
+        }
+      }
+      catch (EvaluateException ignored) {
+      }
+      catch (ClassNotLoadedException ignored) {
+      }
+    }
+    return exceptionObj;
+  }
+
+  public void setAncestor(NodeDescriptor oldDescriptor) {
+    super.setAncestor(oldDescriptor);
+    myIsNew = false;
+    myValue = ((ValueDescriptorImpl)oldDescriptor).getValue();
+  }
+
+  protected void setLvalue(boolean value) {
+    myIsLvalue = value;
+  }
+
+  protected String calcRepresentation(EvaluationContextImpl context, DescriptorLabelListener labelListener){
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+
+    final NodeRenderer renderer = getRenderer(context.getDebugProcess());
+
+    final EvaluateException valueException = myValueException;
+    myIsExpandable = (valueException == null || valueException.getExceptionFromTargetVM() != null) && renderer.isExpandable(getValue(), context, this);
+
+    try {
+      setValueIcon(renderer.calcValueIcon(this, context, labelListener));
+    }
+    catch (EvaluateException e) {
+      LOG.info(e);
+      setValueIcon(null);
+    }
+
+    String label;
+    if (valueException == null) {
+      try {
+        label = renderer.calcLabel(this, context, labelListener);
+      }
+      catch (EvaluateException e) {
+        label = setValueLabelFailed(e);
+      }
+    }
+    else {
+      label = setValueLabelFailed(valueException);
+    }
+
+    return setValueLabel(label);
+  }
+
+  private String getCustomLabel(String label) {
+    //translate only strings in quotes
+    final StringBuilder buf = StringBuilderSpinAllocator.alloc();
+    try {
+      final Value value = getValue();
+      if(isShowIdLabel() && value instanceof ObjectReference) {
+        final String idLabel = getIdLabel((ObjectReference)value);
+        if(!label.startsWith(idLabel)) {
+          buf.append(idLabel);
+        }
+      }
+      if(label == null) {
+        //noinspection HardCodedStringLiteral
+        buf.append("null");
+      }
+      else {
+        buf.append(label);
+      }
+      return buf.toString();
+    }
+    finally {
+      StringBuilderSpinAllocator.dispose(buf);
+    }
+  }
+
+
+  public String setValueLabel(String label) {
+    final String customLabel = getCustomLabel(label);
+    myValueLabel = customLabel;
+    return setLabel(calcValueName() + " = " + customLabel);
+  }
+
+  public String setValueLabelFailed(EvaluateException e) {
+    final String label = setFailed(e);
+    setValueLabel(label);
+    return label;
+  }
+
+  public Icon setValueIcon(Icon icon) {
+    return myValueIcon = icon;
+  }
+
+  @Nullable
+  public Icon getValueIcon() {
+    return myValueIcon;
+  }
+
+  public abstract String calcValueName();
+
+  public void displayAs(NodeDescriptor descriptor) {
+    if (descriptor instanceof ValueDescriptorImpl) {
+      ValueDescriptorImpl valueDescriptor = (ValueDescriptorImpl)descriptor;
+      myRenderer = valueDescriptor.myRenderer;
+    }
+    super.displayAs(descriptor);
+  }
+
+  public Renderer getLastRenderer() {
+    return myRenderer != null ? myRenderer: myAutoRenderer;
+  }
+
+  @Nullable
+  public Type getType() {
+    Value value = getValue();
+    return value != null ? value.type() : null;
+  }
+
+  public NodeRenderer getRenderer (DebugProcessImpl debugProcess) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    Type type = getType();
+    if(type != null && myRenderer != null && myRenderer.isApplicable(type)) {
+      return myRenderer;
+    }
+
+    myAutoRenderer = debugProcess.getAutoRenderer(this);
+    return myAutoRenderer;
+  }
+
+  public void setRenderer(NodeRenderer renderer) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    myRenderer = renderer;
+    myAutoRenderer = null;
+  }
+
+  //returns expression that evaluates tree to this descriptor
+  public PsiExpression getTreeEvaluation(DebuggerTreeNodeImpl debuggerTreeNode, DebuggerContextImpl context) throws EvaluateException {
+    if(debuggerTreeNode.getParent() != null && debuggerTreeNode.getParent().getDescriptor() instanceof ValueDescriptor) {
+      final NodeDescriptorImpl descriptor = debuggerTreeNode.getParent().getDescriptor();
+      final ValueDescriptorImpl vDescriptor = ((ValueDescriptorImpl)descriptor);
+      final PsiExpression parentEvaluation = vDescriptor.getTreeEvaluation(debuggerTreeNode.getParent(), context);
+
+      if (parentEvaluation == null) {
+        return null;
+      }
+
+      return DebuggerTreeNodeExpression.substituteThis(
+        vDescriptor.getRenderer(context.getDebugProcess()).getChildValueExpression(debuggerTreeNode, context),
+        parentEvaluation, vDescriptor.getValue()
+      );
+    }
+
+    return getDescriptorEvaluation(context);
+  }
+
+  //returns expression that evaluates descriptor value
+  //use 'this' to reference parent node
+  //for ex. FieldDescriptorImpl should return
+  //this.fieldName
+  public abstract PsiExpression getDescriptorEvaluation(DebuggerContext context) throws EvaluateException;
+
+  public static String getIdLabel(ObjectReference objRef) {
+    StringBuilder buf = StringBuilderSpinAllocator.alloc();
+    try {
+      final ClassRenderer classRenderer = NodeRendererSettings.getInstance().getClassRenderer();
+      final boolean showConcreteType =
+        !classRenderer.SHOW_DECLARED_TYPE ||
+        (!(objRef instanceof StringReference) && !(objRef instanceof ClassObjectReference) && !isEnumConstant(objRef));
+      if (showConcreteType || classRenderer.SHOW_OBJECT_ID) {
+        buf.append('{');
+        if (showConcreteType) {
+          buf.append(classRenderer.renderTypeName(objRef.type().name()));
+        }
+        if (classRenderer.SHOW_OBJECT_ID) {
+          buf.append('@');
+          if(ApplicationManager.getApplication().isUnitTestMode()) {
+            //noinspection HardCodedStringLiteral
+            buf.append("uniqueID");
+          }
+          else {
+            buf.append(objRef.uniqueID());
+          }
+        }
+        buf.append('}');
+      }
+
+      if (objRef instanceof ArrayReference) {
+        int idx = buf.indexOf("[");
+        if(idx >= 0) {
+          buf.insert(idx + 1, Integer.toString(((ArrayReference)objRef).length()));
+        }
+      }
+
+      return buf.toString();
+    }
+    finally {
+      StringBuilderSpinAllocator.dispose(buf);
+    }
+  }
+
+  private static boolean isEnumConstant(final ObjectReference objRef) {
+    final Type type = objRef.type();
+    return type instanceof ClassType && ((ClassType)type).isEnum();
+  }
+
+  public boolean canSetValue() {
+    return !myIsSynthetic && isLvalue();
+  }
+
+  public String getValueLabel() {
+    return myValueLabel;
+  }
+
+  //Context is set to null
+  public void clear() {
+    super.clear();
+    setValueLabel("");
+    myIsExpandable = false;
+  }
+
+  @Nullable
+  public ValueMarkup getMarkup(final DebugProcess debugProcess) {
+    final Value value = getValue();
+    if (value instanceof ObjectReference) {
+      final ObjectReference objRef = (ObjectReference)value;
+      final Map<ObjectReference, ValueMarkup> map = getMarkupMap(debugProcess);
+      if (map != null) {
+        return map.get(objRef);
+      }
+    }
+    return null;
+  }
+
+  public void setMarkup(final DebugProcess debugProcess, @Nullable final ValueMarkup markup) {
+    final Value value = getValue();
+    if (value instanceof ObjectReference) {
+      final Map<ObjectReference, ValueMarkup> map = getMarkupMap(debugProcess);
+      if (map != null) {
+        final ObjectReference objRef = (ObjectReference)value;
+        if (markup != null) {
+          map.put(objRef, markup);
+        }
+        else {
+          map.remove(objRef);
+        }
+      }
+    }
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/WatchItemDescriptor.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/WatchItemDescriptor.java
new file mode 100644
index 0000000..eaeab2d
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/WatchItemDescriptor.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Class WatchItemDescriptor
+ * @author Jeka
+ */
+package com.intellij.debugger.ui.impl.watch;
+
+import com.intellij.debugger.engine.StackFrameContext;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.debugger.impl.PositionUtil;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Comparing;
+import com.intellij.psi.PsiCodeFragment;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.sun.jdi.Value;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * update(Value, boolean) method must be called whenever the state of the target VM changes
+ */
+public class WatchItemDescriptor extends EvaluationDescriptor {
+
+  @Nullable
+  private String myCustomName = null;
+
+  public WatchItemDescriptor(Project project, TextWithImports text) {
+    super(text, project);
+    setValueLabel("");
+  }
+
+  public WatchItemDescriptor(Project project, TextWithImports text, Value value) {
+    super(text, project, value);
+    setValueLabel("");
+  }
+
+  public String getName() {
+    final String customName = myCustomName;
+    return customName == null? getEvaluationText().getText() : customName;
+  }
+
+  public void setCustomName(@Nullable String customName) {
+    myCustomName = customName;
+  }
+
+  public void setNew() {
+    myIsNew = true;
+  }
+
+  // call update() after setting a new expression
+  public void setEvaluationText(TextWithImports evaluationText) {
+    if (!Comparing.equal(getEvaluationText(), evaluationText)) {
+      setLvalue(false);
+    }
+    myText = evaluationText;
+    myIsNew = true;
+    setValueLabel("");
+  }
+
+  protected EvaluationContextImpl getEvaluationContext(EvaluationContextImpl evaluationContext) {
+    return evaluationContext;
+  }
+
+  protected PsiCodeFragment getEvaluationCode(StackFrameContext context) throws EvaluateException {
+    final PsiElement psiContext = PositionUtil.getContextElement(context);
+    final PsiCodeFragment fragment = getEffectiveCodeFragmentFactory(psiContext).createCodeFragment(getEvaluationText(), psiContext, myProject);
+    fragment.forceResolveScope(GlobalSearchScope.allScope(myProject));
+    return fragment;
+  }
+}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/ArrayElementDescriptor.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/ArrayElementDescriptor.java
new file mode 100644
index 0000000..a2a990d
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/ArrayElementDescriptor.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree;
+
+import com.sun.jdi.ArrayReference;
+
+public interface ArrayElementDescriptor extends NodeDescriptor{
+  ArrayReference getArray();
+  int getIndex();
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/DebuggerTreeNode.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/DebuggerTreeNode.java
new file mode 100644
index 0000000..0825eb2
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/DebuggerTreeNode.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.debugger.ui.tree.render.NodeRenderer;
+
+import javax.swing.tree.MutableTreeNode;
+
+public interface DebuggerTreeNode extends MutableTreeNode{
+  DebuggerTreeNode getParent();
+
+  NodeDescriptor getDescriptor();
+
+  Project getProject();
+
+  void setRenderer(NodeRenderer renderer);
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/FieldDescriptor.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/FieldDescriptor.java
new file mode 100644
index 0000000..4067b87
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/FieldDescriptor.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree;
+
+import com.sun.jdi.Field;
+import com.sun.jdi.ObjectReference;
+
+public interface FieldDescriptor extends NodeDescriptor{
+  Field           getField();
+  ObjectReference getObject();
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/LocalVariableDescriptor.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/LocalVariableDescriptor.java
new file mode 100644
index 0000000..a5f90f4
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/LocalVariableDescriptor.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree;
+
+import com.intellij.debugger.engine.jdi.LocalVariableProxy;
+
+public interface LocalVariableDescriptor extends ValueDescriptor{
+  LocalVariableProxy getLocalVariable();
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/NodeDescriptorFactory.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/NodeDescriptorFactory.java
new file mode 100644
index 0000000..18eb67d
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/NodeDescriptorFactory.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree;
+
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.debugger.engine.jdi.LocalVariableProxy;
+import com.intellij.debugger.ui.impl.watch.UserExpressionDescriptorImpl;
+import com.intellij.debugger.impl.descriptors.data.DescriptorData;
+import com.sun.jdi.ArrayReference;
+import com.sun.jdi.Field;
+import com.sun.jdi.ObjectReference;
+
+/**
+ * creates descriptors
+ * if descriptor was already created in current context (that is location in debugee code) returns that descriptor
+ * else creates new descriptor and restores it's representation properties from history
+ */
+
+public interface NodeDescriptorFactory {
+  ArrayElementDescriptor getArrayItemDescriptor(NodeDescriptor parent, ArrayReference array, int index);
+
+  FieldDescriptor getFieldDescriptor(NodeDescriptor parent, ObjectReference objRef, Field field);
+
+  LocalVariableDescriptor getLocalVariableDescriptor(NodeDescriptor parent, LocalVariableProxy local);
+
+  UserExpressionDescriptor getUserExpressionDescriptor(NodeDescriptor parent, final DescriptorData<UserExpressionDescriptor> data);
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/NodeManager.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/NodeManager.java
new file mode 100644
index 0000000..ff612fe
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/NodeManager.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree;
+
+import com.intellij.debugger.engine.evaluation.EvaluationContext;
+
+public interface NodeManager {
+  DebuggerTreeNode createMessageNode(String s);
+
+  DebuggerTreeNode createNode(NodeDescriptor nodeDescriptor, EvaluationContext evaluationContext);
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/StackFrameDescriptor.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/StackFrameDescriptor.java
new file mode 100644
index 0000000..7712b15
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/StackFrameDescriptor.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree;
+
+import com.intellij.debugger.engine.StackFrameContext;
+import org.jetbrains.annotations.Nullable;
+
+import java.awt.*;
+
+public interface StackFrameDescriptor extends NodeDescriptor, StackFrameContext {
+  @Nullable
+  Color getBackgroundColor();
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/StaticDescriptor.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/StaticDescriptor.java
new file mode 100644
index 0000000..ccd83ad
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/StaticDescriptor.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree;
+
+import com.sun.jdi.ReferenceType;
+
+public interface StaticDescriptor extends NodeDescriptor{
+  ReferenceType getType();
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/ThreadDescriptor.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/ThreadDescriptor.java
new file mode 100644
index 0000000..f4b564d
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/ThreadDescriptor.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree;
+
+import com.intellij.debugger.engine.jdi.ThreadReferenceProxy;
+
+public interface ThreadDescriptor extends NodeDescriptor{
+  public ThreadReferenceProxy getThreadReference();  
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/ThreadGroupDescriptor.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/ThreadGroupDescriptor.java
new file mode 100644
index 0000000..89ba3ce
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/ThreadGroupDescriptor.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree;
+
+import com.intellij.debugger.engine.jdi.ThreadGroupReferenceProxy;
+
+public interface ThreadGroupDescriptor extends NodeDescriptor{
+  ThreadGroupReferenceProxy getThreadGroupReference();
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/UserExpressionDescriptor.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/UserExpressionDescriptor.java
new file mode 100644
index 0000000..5641d82
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/UserExpressionDescriptor.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree;
+
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+
+public interface UserExpressionDescriptor extends ValueDescriptor {
+  public void setContext(EvaluationContextImpl evaluationContext);
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/ValueDescriptor.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/ValueDescriptor.java
new file mode 100644
index 0000000..d4a444e
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/ValueDescriptor.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree;
+
+import com.intellij.debugger.DebuggerContext;
+import com.intellij.debugger.engine.DebugProcess;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.psi.PsiExpression;
+import com.intellij.xdebugger.impl.ui.tree.ValueMarkup;
+import com.sun.jdi.Value;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+
+public interface ValueDescriptor extends NodeDescriptor{
+  PsiExpression getDescriptorEvaluation(DebuggerContext context) throws EvaluateException;
+
+  Value getValue();
+
+  String setValueLabel(String label);
+
+  String setValueLabelFailed(EvaluateException e);
+
+  Icon setValueIcon(Icon icon);
+
+  boolean isArray();
+  boolean isLvalue();
+  boolean isNull();
+  boolean isPrimitive();
+  boolean isString();
+  
+  @Nullable
+  ValueMarkup getMarkup(final DebugProcess debugProcess);
+  
+  void setMarkup(final DebugProcess debugProcess, @Nullable ValueMarkup markup);
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/actions/ShowAllAs.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/actions/ShowAllAs.java
new file mode 100644
index 0000000..9e713a3
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/actions/ShowAllAs.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree.actions;
+
+import com.intellij.debugger.DebuggerContext;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.engine.DebuggerUtils;
+import com.intellij.debugger.engine.SuspendContext;
+import com.intellij.debugger.engine.managerThread.SuspendContextCommand;
+import com.intellij.debugger.ui.tree.DebuggerTreeNode;
+import com.intellij.debugger.ui.tree.ValueDescriptor;
+import com.intellij.debugger.ui.tree.render.NodeRenderer;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.sun.jdi.*;
+
+import java.util.Enumeration;
+
+public class ShowAllAs extends AnAction {
+  private final NodeRenderer myRenderer;
+
+  public ShowAllAs(NodeRenderer renderer) {
+    myRenderer = renderer;
+  }
+
+  private boolean isPrimitiveArray(DebuggerTreeNode selectedNode) {
+    try {
+      if(selectedNode.getDescriptor() instanceof ValueDescriptor) {
+        ValueDescriptor valueDescriptor = ((ValueDescriptor)selectedNode.getDescriptor());
+        if(valueDescriptor.isArray()) {
+          ArrayReference arrayReference = ((ArrayReference)valueDescriptor.getValue());
+          Type componentType = ((ArrayType)arrayReference.type()).componentType();
+          if(componentType instanceof PrimitiveType) {
+            if(componentType instanceof ByteType ||
+               componentType instanceof ShortType ||
+               componentType instanceof IntegerType ||
+               componentType instanceof LongType) {
+              return true;
+            }
+          }
+        }
+      }
+    }
+    catch (ClassNotLoadedException e) {
+    }
+    return false;
+  }
+
+  public void update(AnActionEvent e) {
+    DebuggerTreeNode selectedNode = ((DebuggerUtilsEx)DebuggerUtils.getInstance()).getSelectedNode(e.getDataContext());
+    e.getPresentation().setVisible(myRenderer != null && selectedNode != null && isPrimitiveArray(selectedNode));
+  }
+
+  public void actionPerformed(AnActionEvent e) {
+    DebuggerTreeNode selectedNode = ((DebuggerUtilsEx)DebuggerUtils.getInstance()).getSelectedNode(e.getDataContext());
+    if(selectedNode == null) return;
+    
+    if(!isPrimitiveArray(selectedNode)) return;
+
+    final DebuggerContext debuggerContext = DebuggerUtils.getInstance().getDebuggerContext(e.getDataContext());
+    if(debuggerContext == null || debuggerContext.getDebugProcess() == null) return;
+
+    for(Enumeration children = selectedNode.children(); children.hasMoreElements(); ) {
+      final DebuggerTreeNode child = (DebuggerTreeNode)children.nextElement();
+      if(child.getDescriptor() instanceof ValueDescriptor) {
+        debuggerContext.getDebugProcess().getManagerThread().invokeCommand(new SuspendContextCommand() {
+          public SuspendContext getSuspendContext() {
+            return debuggerContext.getSuspendContext();
+          }
+
+          public void action() {
+            child.setRenderer(myRenderer);
+          }
+
+          public void commandCancelled() {
+          }
+        });
+      }
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/actions/ShowAllAsDecimal.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/actions/ShowAllAsDecimal.java
new file mode 100644
index 0000000..9fd2f90
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/actions/ShowAllAsDecimal.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree.actions;
+
+import com.intellij.debugger.settings.NodeRendererSettings;
+
+
+public class ShowAllAsDecimal extends ShowAllAs{
+  public ShowAllAsDecimal() {
+    super(NodeRendererSettings.getInstance().getPrimitiveRenderer());
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/actions/ShowAllAsHex.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/actions/ShowAllAsHex.java
new file mode 100644
index 0000000..cbf9376
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/actions/ShowAllAsHex.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree.actions;
+
+import com.intellij.debugger.ui.tree.render.HexRenderer;
+import com.intellij.debugger.ui.tree.render.NodeRenderer;
+import com.intellij.debugger.settings.NodeRendererSettings;
+
+import java.util.List;
+import java.util.Iterator;
+
+public class ShowAllAsHex extends ShowAllAs {
+
+  public ShowAllAsHex() {
+    super(NodeRendererSettings.getInstance().getHexRenderer());
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ArrayRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ArrayRenderer.java
new file mode 100644
index 0000000..54a2c60
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ArrayRenderer.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree.render;
+
+import com.intellij.debugger.DebuggerContext;
+import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContext;
+import com.intellij.debugger.settings.ViewsGeneralSettings;
+import com.intellij.debugger.ui.impl.watch.ArrayElementDescriptorImpl;
+import com.intellij.debugger.ui.impl.watch.MessageDescriptor;
+import com.intellij.debugger.ui.impl.watch.NodeManagerImpl;
+import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl;
+import com.intellij.debugger.ui.tree.DebuggerTreeNode;
+import com.intellij.debugger.ui.tree.NodeDescriptor;
+import com.intellij.debugger.ui.tree.NodeDescriptorFactory;
+import com.intellij.debugger.ui.tree.ValueDescriptor;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.roots.LanguageLevelProjectExtension;
+import com.intellij.openapi.util.DefaultJDOMExternalizer;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.pom.java.LanguageLevel;
+import com.intellij.psi.JavaPsiFacade;
+import com.intellij.psi.PsiElementFactory;
+import com.intellij.psi.PsiExpression;
+import com.intellij.util.IncorrectOperationException;
+import com.sun.jdi.ArrayReference;
+import com.sun.jdi.ArrayType;
+import com.sun.jdi.Type;
+import com.sun.jdi.Value;
+import org.jdom.Element;
+import org.jetbrains.annotations.NonNls;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ListIterator;
+
+/**
+ * User: lex
+ * Date: Sep 18, 2003
+ * Time: 3:07:19 PM
+ */
+public class ArrayRenderer extends NodeRendererImpl{
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.tree.render.ArrayRenderer");
+  
+  public static final @NonNls String UNIQUE_ID = "ArrayRenderer";
+
+  public int START_INDEX = 0;
+  public int END_INDEX   = 100;
+  public int ENTRIES_LIMIT = 101;
+  private final static String MORE_ELEMENTS = "...";
+
+  public ArrayRenderer() {
+    myProperties.setEnabled(true);
+  }
+
+  public String getUniqueId() {
+    return UNIQUE_ID;
+  }
+
+  public boolean isEnabled() {
+    return myProperties.isEnabled();
+  }
+
+  public void setEnabled(boolean enabled) {
+    myProperties.setEnabled(enabled);
+  }
+
+  public @NonNls String getName() {
+    return "Array";
+  }
+
+  public void setName(String text) {
+    LOG.assertTrue(false);
+  }
+
+  public ArrayRenderer clone() {
+    return (ArrayRenderer)super.clone();
+  }
+
+  public String calcLabel(ValueDescriptor descriptor, EvaluationContext evaluationContext, DescriptorLabelListener listener) throws EvaluateException {
+    return ClassRenderer.calcLabel(descriptor);
+  }
+
+  public void buildChildren(Value value, ChildrenBuilder builder, EvaluationContext evaluationContext) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    List<DebuggerTreeNode> children = new ArrayList<DebuggerTreeNode>();
+    NodeManagerImpl nodeManager = (NodeManagerImpl)builder.getNodeManager();
+    NodeDescriptorFactory descriptorFactory = builder.getDescriptorManager();
+
+    ArrayReference array = (ArrayReference)value;
+    if (array.length() > 0) {
+      int added = 0;
+
+      if(ENTRIES_LIMIT > END_INDEX - START_INDEX + 1) {
+        ENTRIES_LIMIT = END_INDEX - START_INDEX;
+      }
+
+      if(ENTRIES_LIMIT <= 0) {
+        ENTRIES_LIMIT = 1;
+      }
+
+      if(array.length() - 1 >= START_INDEX) {
+        int start = START_INDEX;
+        int end  = array.length() - 1 < END_INDEX   ? array.length() - 1 : END_INDEX;
+
+        int idx;
+
+        for (idx = start; idx <= end; idx++) {
+          DebuggerTreeNode arrayItemNode = nodeManager.createNode(descriptorFactory.getArrayItemDescriptor(builder.getParentDescriptor(), array, idx), evaluationContext);
+
+          if (ViewsGeneralSettings.getInstance().HIDE_NULL_ARRAY_ELEMENTS && ((ValueDescriptorImpl)arrayItemNode.getDescriptor()).isNull()) continue;
+          if(added >= (ENTRIES_LIMIT  + 1)/ 2) break;
+          children.add(arrayItemNode);
+          added++;
+        }
+
+        start = idx;
+
+        List<DebuggerTreeNode> childrenTail = new ArrayList<DebuggerTreeNode>();
+        for (idx = end; idx >= start; idx--) {
+          DebuggerTreeNode arrayItemNode = nodeManager.createNode(descriptorFactory.getArrayItemDescriptor(builder.getParentDescriptor(), array, idx), evaluationContext);
+
+          if (ViewsGeneralSettings.getInstance().HIDE_NULL_ARRAY_ELEMENTS && ((ValueDescriptorImpl)arrayItemNode.getDescriptor()).isNull()) continue;
+          if(added >= ENTRIES_LIMIT) break;
+          childrenTail.add(arrayItemNode);
+          added++;
+        }
+
+        //array is printed in the following way
+        // ...
+        // items1...itemENTRIES_LIMIT/2
+        // ...
+        // itemENTRIES_LIMIT/2+1...itemENTRIES_LIMIT
+        // ...
+
+        //when itemENTRIES_LIMIT/2+1...itemENTRIES_LIMIT set is empty, we should not add middle "..." node
+        if(idx >= start && !(ENTRIES_LIMIT == 1 && END_INDEX < array.length())) {
+          children.add(nodeManager.createMessageNode(new MessageDescriptor(MORE_ELEMENTS, MessageDescriptor.SPECIAL)));
+        }
+
+        for (ListIterator<DebuggerTreeNode> iterator = childrenTail.listIterator(childrenTail.size()); iterator.hasPrevious();) {
+          DebuggerTreeNode debuggerTreeNode = iterator.previous();
+          children.add(debuggerTreeNode);
+        }
+      }
+
+      if (added == 0) {
+        if(START_INDEX == 0 && array.length() - 1 <= END_INDEX) {
+          children.add(nodeManager.createMessageNode(MessageDescriptor.ALL_ELEMENTS_IN_RANGE_ARE_NULL.getLabel()));
+        }
+        else {
+          children.add(nodeManager.createMessageNode(MessageDescriptor.ALL_ELEMENTS_IN_VISIBLE_RANGE_ARE_NULL.getLabel()));
+        }
+      }
+      else {
+        if(START_INDEX > 0) {
+          children.add(0, nodeManager.createMessageNode(new MessageDescriptor(MORE_ELEMENTS, MessageDescriptor.SPECIAL)));
+        }
+
+        if(END_INDEX < array.length() - 1) {
+          children.add(nodeManager.createMessageNode(new MessageDescriptor(MORE_ELEMENTS, MessageDescriptor.SPECIAL)));
+        }
+      }
+    }
+    builder.setChildren(children);
+  }
+
+  public void readExternal(Element element) throws InvalidDataException {
+    super.readExternal(element);
+    DefaultJDOMExternalizer.readExternal(this, element);
+  }
+
+  public void writeExternal(Element element) throws WriteExternalException {
+    super.writeExternal(element);
+    DefaultJDOMExternalizer.writeExternal(this, element);
+  }
+
+  public PsiExpression getChildValueExpression(DebuggerTreeNode node, DebuggerContext context) {
+    LOG.assertTrue(node.getDescriptor() instanceof ArrayElementDescriptorImpl, node.getDescriptor().getClass().getName());
+    ArrayElementDescriptorImpl descriptor = (ArrayElementDescriptorImpl)node.getDescriptor();
+
+    PsiElementFactory elementFactory = JavaPsiFacade.getInstance(node.getProject()).getElementFactory();
+    try {
+      LanguageLevel languageLevel = LanguageLevelProjectExtension.getInstance(node.getProject()).getLanguageLevel();
+      return elementFactory.createExpressionFromText("this[" + descriptor.getIndex() + "]", elementFactory.getArrayClass(languageLevel));
+    }
+    catch (IncorrectOperationException e) {
+      LOG.error(e);
+      return null;
+    }
+  }
+
+  public boolean isExpandable(Value value, EvaluationContext evaluationContext, NodeDescriptor parentDescriptor) {
+    return value instanceof ArrayReference && ((ArrayReference)value).length() > 0;
+  }
+
+  public boolean isApplicable(Type type) {
+    return (type instanceof ArrayType);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/BasicRendererProperties.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/BasicRendererProperties.java
new file mode 100644
index 0000000..d00e601
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/BasicRendererProperties.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree.render;
+
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.JDOMExternalizable;
+import com.intellij.openapi.util.WriteExternalException;
+import org.jdom.Element;
+import org.jetbrains.annotations.NonNls;
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: Feb 12, 2005
+ */
+public final class BasicRendererProperties implements Cloneable, JDOMExternalizable{
+  // todo: add class filters here
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.tree.render.BasicRendererProperties");
+
+  private static final @NonNls String NAME_OPTION = "NAME";
+  private String myName;
+
+  private static final @NonNls String ENABLED_OPTION = "ENABLED";
+  private Boolean myEnabled;
+
+  private static final @NonNls String CLASSNAME_OPTION = "QUALIFIED_NAME";
+  private String myClassName;
+
+  public String getName() {
+    return myName;
+  }
+
+  public void setName(final String name) {
+    myName = name;
+  }
+
+  public boolean isEnabled() {
+    return myEnabled != null? myEnabled.booleanValue() : false;
+  }
+
+  public void setEnabled(final boolean enabled) {
+    myEnabled = enabled? Boolean.TRUE : Boolean.FALSE;
+  }
+
+  public String getClassName() {
+    return myClassName;
+  }
+
+  public void setClassName(final String className) {
+    myClassName = className;
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"}) public void readExternal(Element element) throws InvalidDataException {
+    final List options = element.getChildren("option");
+    myName = null;
+    myEnabled = null;
+    myClassName = null;
+    for (Iterator it = options.iterator(); it.hasNext();) {
+      final Element option = (Element)it.next();
+      final String optionName = option.getAttributeValue("name");
+      if (NAME_OPTION.equals(optionName)) {
+        myName = option.getAttributeValue("value");
+      }
+      else if (ENABLED_OPTION.equals(optionName)) {
+        final String val = option.getAttributeValue("value");
+        myEnabled = "true".equalsIgnoreCase(val)? Boolean.TRUE : Boolean.FALSE;
+      }
+      else if (CLASSNAME_OPTION.equals(optionName)) {
+        myClassName = option.getAttributeValue("value");
+      }
+    }
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"}) public void writeExternal(Element element) throws WriteExternalException {
+    if (myName != null) {
+      addOption(element, NAME_OPTION, myName);
+    }
+    if (myEnabled != null) {
+      addOption(element, ENABLED_OPTION, myEnabled.booleanValue()? "true" : "false");
+    }
+    if (myClassName != null) {
+      addOption(element, CLASSNAME_OPTION, myClassName);
+    }
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  private void addOption(final Element element, final String optionName, final String optionValue) {
+    final Element option = new Element("option");
+    element.addContent(option);
+    option.setAttribute("name", optionName);
+    option.setAttribute("value", optionValue);
+  }
+
+  public BasicRendererProperties clone()  {
+    try {
+      return (BasicRendererProperties)super.clone();
+    }
+    catch (CloneNotSupportedException e) {
+      LOG.error(e);
+    }
+    return null;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/BatchEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/BatchEvaluator.java
new file mode 100644
index 0000000..abf937e
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/BatchEvaluator.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree.render;
+
+import com.intellij.debugger.DebuggerManager;
+import com.intellij.debugger.engine.DebugProcess;
+import com.intellij.debugger.engine.DebugProcessAdapter;
+import com.intellij.debugger.engine.SuspendContext;
+import com.intellij.debugger.engine.SuspendContextImpl;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.engine.evaluation.EvaluationContext;
+import com.intellij.debugger.engine.jdi.ThreadReferenceProxy;
+import com.intellij.debugger.engine.managerThread.SuspendContextCommand;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.Key;
+import com.intellij.rt.debugger.BatchEvaluatorServer;
+import com.intellij.util.containers.HashMap;
+import com.sun.jdi.*;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * User: lex
+ * Date: Jul 7, 2003
+ * Time: 11:13:52 PM
+ */
+
+public class BatchEvaluator {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.tree.render.BatchEvaluator");
+
+  private final DebugProcess myDebugProcess;
+  private boolean myBatchEvaluatorChecked;
+  private ObjectReference myBatchEvaluatorObject;
+  private Method myBatchEvaluatorMethod;
+
+  private static final Key<BatchEvaluator> BATCH_EVALUATOR_KEY = new Key<BatchEvaluator>("BatchEvaluator");
+  public static final Key<Boolean> REMOTE_SESSION_KEY = new Key<Boolean>("is_remote_session_key");
+
+  private final HashMap<SuspendContext, List<ToStringCommand>> myBuffer = new HashMap<SuspendContext, List<ToStringCommand>>();
+
+  private BatchEvaluator(DebugProcess process) {
+    myDebugProcess = process;
+    myDebugProcess.addDebugProcessListener(new DebugProcessAdapter() {
+      public void processDetached(DebugProcess process, boolean closedByUser) {
+        myBatchEvaluatorChecked = false;
+        myBatchEvaluatorObject= null;
+        myBatchEvaluatorMethod = null;
+      }
+    });
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"}) public boolean hasBatchEvaluator(EvaluationContext evaluationContext) {
+    if (!myBatchEvaluatorChecked) {
+      myBatchEvaluatorChecked = true;
+      final Boolean isRemote = myDebugProcess.getUserData(REMOTE_SESSION_KEY);
+      if (isRemote != null && isRemote.booleanValue()) {
+        // optimization: for remote sessions the BatchEvaluator is not there for sure
+        return false;
+      }
+
+      ThreadReferenceProxy thread = evaluationContext.getSuspendContext().getThread();
+
+      if (thread == null) {
+        return false;
+      }
+
+      ThreadReference threadReference = thread.getThreadReference();
+      if(threadReference == null) {
+        return false;
+      }
+
+      ClassType batchEvaluatorClass = null;
+      try {
+        batchEvaluatorClass = (ClassType)myDebugProcess.findClass(evaluationContext, BatchEvaluatorServer.class.getName(),
+          evaluationContext.getClassLoader());
+      }
+      catch (EvaluateException e) {
+      }
+
+      if (batchEvaluatorClass != null) {
+        Method constructor = batchEvaluatorClass.concreteMethodByName("<init>", "()V");
+        if(constructor != null){
+          ObjectReference evaluator = null;
+          try {
+            evaluator = myDebugProcess.newInstance(evaluationContext, batchEvaluatorClass, constructor, new ArrayList());
+          }
+          catch (Exception e) {
+            LOG.debug(e);
+          }
+          myBatchEvaluatorObject = evaluator;
+
+          if(myBatchEvaluatorObject != null) {
+            myBatchEvaluatorMethod = batchEvaluatorClass.concreteMethodByName("evaluate", "([Ljava/lang/Object;)[Ljava/lang/Object;");
+          }
+        }
+      }
+    }
+    return myBatchEvaluatorMethod != null;
+  }
+
+  public void invoke(ToStringCommand command) {
+    LOG.assertTrue(DebuggerManager.getInstance(myDebugProcess.getProject()).isDebuggerManagerThread());
+
+    final EvaluationContext evaluationContext = command.getEvaluationContext();
+    final SuspendContext suspendContext = evaluationContext.getSuspendContext();
+
+    if(!hasBatchEvaluator(evaluationContext)) {
+      myDebugProcess.getManagerThread().invokeCommand(command);
+    }
+    else {
+      List<ToStringCommand> toStringCommands = myBuffer.get(suspendContext);
+      if(toStringCommands == null) {
+        final List<ToStringCommand> commands = new ArrayList<ToStringCommand>();
+        toStringCommands = commands;
+        myBuffer.put(suspendContext, commands);
+
+        myDebugProcess.getManagerThread().invokeCommand(new SuspendContextCommand() {
+          public SuspendContext getSuspendContext() {
+            return suspendContext;
+          }
+
+          public void action() {
+            myBuffer.remove(suspendContext);
+
+            if(!doEvaluateBatch(commands, evaluationContext)) {
+              for (Iterator<ToStringCommand> iterator = commands.iterator(); iterator.hasNext();) {
+                ToStringCommand toStringCommand = iterator.next();
+                toStringCommand.action();
+              }
+            }
+          }
+
+          public void commandCancelled() {
+            myBuffer.remove(suspendContext);
+          }
+        });
+      }
+
+      toStringCommands.add(command);
+    }
+  }
+
+  public static BatchEvaluator getBatchEvaluator(DebugProcess debugProcess) {
+    BatchEvaluator batchEvaluator = debugProcess.getUserData(BATCH_EVALUATOR_KEY);
+
+    if(batchEvaluator == null) {
+      batchEvaluator = new BatchEvaluator(debugProcess);
+      debugProcess.putUserData(BATCH_EVALUATOR_KEY, batchEvaluator);
+    }
+    return batchEvaluator;
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  private boolean doEvaluateBatch(List<ToStringCommand> requests, EvaluationContext evaluationContext) {
+    try {
+      DebugProcess debugProcess = evaluationContext.getDebugProcess();
+      List<Value> values = new ArrayList<Value>();
+      for (Iterator<ToStringCommand> iterator = requests.iterator(); iterator.hasNext();) {
+        ToStringCommand toStringCommand = iterator.next();
+        final Value value = toStringCommand.getValue();
+        values.add(value instanceof ObjectReference? ((ObjectReference)value) : value);
+      }
+
+      ArrayType objectArrayClass = (ArrayType)debugProcess.findClass(
+        evaluationContext,
+        "java.lang.Object[]",
+        evaluationContext.getClassLoader());
+      if (objectArrayClass == null) {
+        return false;
+      }
+
+      ArrayReference argArray = debugProcess.newInstance(objectArrayClass, values.size());
+      ((SuspendContextImpl)evaluationContext.getSuspendContext()).keep(argArray); // to avoid ObjectCollectedException
+      argArray.setValues(values);
+      List argList = new ArrayList(1);
+      argList.add(argArray);
+      Value value = debugProcess.invokeMethod(evaluationContext, myBatchEvaluatorObject,
+                                              myBatchEvaluatorMethod, argList);
+      if (value instanceof ArrayReference) {
+        ((SuspendContextImpl)evaluationContext.getSuspendContext()).keep((ArrayReference)value); // to avoid ObjectCollectedException for both the array and its elements
+        final ArrayReference strings = (ArrayReference)value;
+        final List<Value> allValuesArray = strings.getValues();
+        final Value[] allValues = allValuesArray.toArray(new Value[allValuesArray.size()]);
+        int idx = 0;
+        for (Iterator<ToStringCommand> iterator = requests.iterator(); iterator.hasNext(); idx++) {
+          ToStringCommand request = iterator.next();
+          final Value strValue = allValues[idx];
+          if(strValue == null || strValue instanceof StringReference){
+            try {
+              String str = (strValue == null)? null : ((StringReference)strValue).value();
+              request.evaluationResult(str);
+            }
+            catch (ObjectCollectedException e) {
+              // ignored
+            }
+          } 
+          else if(strValue instanceof ObjectReference){
+            request.evaluationError(EvaluateExceptionUtil.createEvaluateException(new InvocationException((ObjectReference)strValue)).getMessage());
+          } 
+          else {
+            LOG.assertTrue(false);
+          }
+          request.setEvaluated();
+        }
+      }
+      return true;
+    }
+    catch (ClassNotLoadedException e) {
+    }
+    catch (InvalidTypeException e) {
+    }
+    catch (EvaluateException e) {
+    }
+    catch (ObjectCollectedException e) {
+    }
+    return false;
+  }
+
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/CachedEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/CachedEvaluator.java
new file mode 100644
index 0000000..2861e2a
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/CachedEvaluator.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree.render;
+
+import com.intellij.debugger.engine.DebuggerUtils;
+import com.intellij.debugger.engine.evaluation.*;
+import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Computable;
+import com.intellij.psi.*;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.reference.SoftReference;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: lex
+ * Date: Dec 27, 2003
+ * Time: 7:56:13 PM
+ * To change this template use Options | File Templates.
+ */
+public abstract class CachedEvaluator {
+  private final CodeFragmentFactory myDefaultFragmentFactory;
+
+  public CachedEvaluator() {
+    myDefaultFragmentFactory = new CodeFragmentFactoryContextWrapper(DefaultCodeFragmentFactory.getInstance());
+  }
+
+  private static class Cache {
+    protected ExpressionEvaluator myEvaluator;
+    protected EvaluateException   myException;
+    protected PsiExpression       myPsiChildrenExpression;
+  }
+  
+  SoftReference<Cache> myCache = new SoftReference<Cache>(null);
+  private TextWithImports myReferenceExpression;
+
+  protected abstract String getClassName();
+
+  public TextWithImports getReferenceExpression() {
+    return myReferenceExpression != null ? myReferenceExpression : DebuggerUtils.getInstance().createExpressionWithImports("");
+  }
+
+  public void setReferenceExpression(TextWithImports referenceExpression) {
+    myReferenceExpression = referenceExpression;
+    clear();
+  }
+
+  public void clear() {
+    myCache.clear();
+  }
+
+  protected Cache initEvaluatorAndChildrenExpression(final Project project) {
+    final Cache cache = new Cache();
+    try {
+      final PsiClass contextClass = DebuggerUtils.findClass(getClassName(), project, GlobalSearchScope.allScope(project));
+      if(contextClass == null) {
+        throw EvaluateExceptionUtil.CANNOT_FIND_SOURCE_CLASS;
+      }
+      final PsiType contextType = DebuggerUtils.getType(getClassName(), project);
+      cache.myPsiChildrenExpression = null;
+      JavaCodeFragment codeFragment = myDefaultFragmentFactory.createCodeFragment(myReferenceExpression, contextClass, project);
+      codeFragment.forceResolveScope(GlobalSearchScope.allScope(project));
+      codeFragment.setThisType(contextType);
+      DebuggerUtils.checkSyntax(codeFragment);
+      cache.myPsiChildrenExpression = ((PsiExpressionCodeFragment)codeFragment).getExpression();
+      cache.myEvaluator = myDefaultFragmentFactory.getEvaluatorBuilder().build(cache.myPsiChildrenExpression, null);
+    }
+    catch (EvaluateException e) {
+      cache.myException = e;
+    }
+
+    myCache = new SoftReference<Cache>(cache);
+    return cache;
+  }
+
+  protected ExpressionEvaluator getEvaluator(final Project project) throws EvaluateException {
+    Cache cache = myCache.get();
+    if(cache == null) {
+      cache = PsiDocumentManager.getInstance(project).commitAndRunReadAction(new Computable<Cache>() {
+        public Cache compute() {
+          return initEvaluatorAndChildrenExpression(project);
+        }
+      });
+    }
+
+    if(cache.myException != null) {
+      throw cache.myException;
+    }
+
+    return cache.myEvaluator;
+  }
+
+  protected PsiExpression getPsiExpression(final Project project) {
+    Cache cache = myCache.get();
+    if(cache == null) {
+      cache = initEvaluatorAndChildrenExpression(project);
+    }
+
+    return cache.myPsiChildrenExpression;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ChildrenBuilder.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ChildrenBuilder.java
new file mode 100644
index 0000000..8a1f358
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ChildrenBuilder.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree.render;
+
+import com.intellij.debugger.ui.tree.*;
+
+import java.util.List;
+
+public interface ChildrenBuilder {
+  NodeDescriptorFactory  getDescriptorManager();
+
+  NodeManager getNodeManager();
+    
+  ValueDescriptor getParentDescriptor();
+
+  void setChildren(List<DebuggerTreeNode> children);
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ChildrenRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ChildrenRenderer.java
new file mode 100644
index 0000000..969635a
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ChildrenRenderer.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree.render;
+
+import com.intellij.debugger.DebuggerContext;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContext;
+import com.intellij.debugger.ui.tree.DebuggerTreeNode;
+import com.intellij.debugger.ui.tree.NodeDescriptor;
+import com.intellij.psi.PsiExpression;
+import com.sun.jdi.Value;
+
+public interface ChildrenRenderer extends Renderer {
+  void buildChildren(Value value, ChildrenBuilder  builder, EvaluationContext evaluationContext);
+
+  /**
+   * - parentNode
+   *    + ..
+   *    + node
+   *    + ...
+   *
+   * is invoked on the renderer of the parentNode
+   * @param node a child node
+   * @return expression that evaluates the child node.
+   *         Use 'this' to refer the expression that evaluates this (parent) node
+   * @param context
+   */
+  PsiExpression getChildValueExpression(DebuggerTreeNode node, DebuggerContext context) throws EvaluateException;
+
+  boolean isExpandable(Value value, EvaluationContext evaluationContext, NodeDescriptor parentDescriptor);
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ClassRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ClassRenderer.java
new file mode 100644
index 0000000..bdf89a5
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ClassRenderer.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree.render;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerContext;
+import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
+import com.intellij.debugger.engine.DebuggerUtils;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContext;
+import com.intellij.debugger.engine.jdi.StackFrameProxy;
+import com.intellij.debugger.ui.impl.watch.FieldDescriptorImpl;
+import com.intellij.debugger.ui.impl.watch.MessageDescriptor;
+import com.intellij.debugger.ui.impl.watch.NodeManagerImpl;
+import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl;
+import com.intellij.debugger.ui.tree.*;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.Comparing;
+import com.intellij.openapi.util.DefaultJDOMExternalizer;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.JavaPsiFacade;
+import com.intellij.psi.PsiElementFactory;
+import com.intellij.psi.PsiExpression;
+import com.intellij.util.IncorrectOperationException;
+import com.intellij.util.StringBuilderSpinAllocator;
+import com.sun.jdi.*;
+import org.jdom.Element;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * User: lex
+ * Date: Sep 17, 2003
+ * Time: 2:04:00 PM
+ */
+public class ClassRenderer extends NodeRendererImpl{
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.tree.render.ClassRenderer");
+  
+  public static final @NonNls String UNIQUE_ID = "ClassRenderer";
+
+  public boolean SORT_ASCENDING = false;
+  public boolean SHOW_SYNTHETICS = true;
+  public boolean SHOW_VAL_FIELDS_AS_LOCAL_VARIABLES = true;
+  public boolean SHOW_STATIC = false;
+  public boolean SHOW_STATIC_FINAL = false;
+
+  public boolean SHOW_FQ_TYPE_NAMES = true;
+  public boolean SHOW_DECLARED_TYPE = false;
+  public boolean SHOW_OBJECT_ID = true;
+  
+  public ClassRenderer() {
+    myProperties.setEnabled(true);
+  }
+
+  public final String renderTypeName(final String typeName) {
+    if (SHOW_FQ_TYPE_NAMES) {
+      return typeName;
+    }
+    final int dotIndex = typeName.lastIndexOf('.');
+    if (dotIndex > 0) {
+      return typeName.substring(dotIndex + 1);
+    }
+    return typeName;
+  }
+
+  public String getUniqueId() {
+    return UNIQUE_ID;
+  }
+
+  public boolean isEnabled() {
+    return myProperties.isEnabled();
+  }
+
+  public void setEnabled(boolean enabled) {
+    myProperties.setEnabled(enabled);
+  }
+
+  public ClassRenderer clone() {
+    return (ClassRenderer) super.clone();
+  }
+
+  public String calcLabel(ValueDescriptor descriptor, EvaluationContext evaluationContext, DescriptorLabelListener labelListener)  throws EvaluateException {
+    return calcLabel(descriptor);
+  }
+
+  protected static String calcLabel(ValueDescriptor descriptor) {
+    final ValueDescriptorImpl valueDescriptor = (ValueDescriptorImpl)descriptor;
+    final Value value = valueDescriptor.getValue();
+    if (value instanceof ObjectReference) {
+      final StringBuilder buf = StringBuilderSpinAllocator.alloc();
+      try {
+        if (value instanceof StringReference) {
+          buf.append('\"');
+          buf.append(DebuggerUtils.convertToPresentationString(((StringReference)value).value()));
+          buf.append('\"');
+        }
+        else if (value instanceof ClassObjectReference) {
+          ReferenceType type = ((ClassObjectReference)value).reflectedType();
+          buf.append((type != null)?type.name():"{...}");
+        }
+        else {
+          final ObjectReference objRef = (ObjectReference)value;
+          final Type type = objRef.type();
+          if (type instanceof ClassType && ((ClassType)type).isEnum()) {
+            final String name = getEnumConstantName(objRef, (ClassType)type);
+            if (name != null) {
+              buf.append(name);
+            }
+            else {
+              buf.append(type.name());
+            }
+          }
+          else {
+            buf.append(ValueDescriptorImpl.getIdLabel(objRef));
+          }
+        }
+        return buf.toString();
+      }
+      finally {
+        StringBuilderSpinAllocator.dispose(buf);
+      }
+    }
+    else if(value == null) {
+      //noinspection HardCodedStringLiteral
+      return "null";
+    }
+    else {
+      return DebuggerBundle.message("label.undefined");
+    }
+  }
+
+  public void buildChildren(final Value value, final ChildrenBuilder builder, final EvaluationContext evaluationContext) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    final ValueDescriptorImpl parentDescriptor = (ValueDescriptorImpl)builder.getParentDescriptor();
+    final NodeManager nodeManager = builder.getNodeManager();
+    final NodeDescriptorFactory nodeDescriptorFactory = builder.getDescriptorManager();
+
+    List<DebuggerTreeNode> children = new ArrayList<DebuggerTreeNode>();
+    if (value instanceof ObjectReference) {
+      final ObjectReference objRef = (ObjectReference)value;
+      final ReferenceType refType = objRef.referenceType();
+      // default ObjectReference processing
+      final List<Field> fields = refType.allFields();
+      if (fields.size() > 0) {
+        for (final Field field : fields) {
+          if (!shouldDisplay(evaluationContext, objRef, field)) {
+            continue;
+          }
+          children.add(nodeManager.createNode(nodeDescriptorFactory.getFieldDescriptor(parentDescriptor, objRef, field), evaluationContext));
+        }
+
+        if(SORT_ASCENDING) {
+          Collections.sort(children, NodeManagerImpl.getNodeComparator());
+        }
+      }
+      else {
+        children.add(nodeManager.createMessageNode(MessageDescriptor.CLASS_HAS_NO_FIELDS.getLabel()));
+      }
+    }
+    builder.setChildren(children);
+  }
+
+  private boolean shouldDisplay(EvaluationContext context, @NotNull ObjectReference objInstance, @NotNull Field field) {
+    final boolean isSynthetic = DebuggerUtils.isSynthetic(field);
+    if (!SHOW_SYNTHETICS && isSynthetic) {
+      return false;
+    }
+    if (SHOW_VAL_FIELDS_AS_LOCAL_VARIABLES && isSynthetic) {
+      try {
+        final StackFrameProxy frameProxy = context.getFrameProxy();
+        if (frameProxy != null) {
+          final Location location = frameProxy.location();
+          if (location != null && objInstance.equals(context.getThisObject()) && Comparing.equal(objInstance.referenceType(), location.declaringType()) && StringUtil.startsWith(field.name(), FieldDescriptorImpl.OUTER_LOCAL_VAR_FIELD_PREFIX)) {
+            return false;
+          }
+        }
+      }
+      catch (EvaluateException ignored) {
+      }
+    }
+    if(!SHOW_STATIC && field.isStatic()) {
+      return false;
+    }
+
+    if(!SHOW_STATIC_FINAL && field.isStatic() && field.isFinal()) {
+      return false;
+    }
+
+    return true;
+  }
+
+  public void readExternal(Element element) throws InvalidDataException {
+    super.readExternal(element);
+    DefaultJDOMExternalizer.readExternal(this, element);
+  }
+
+  public void writeExternal(Element element) throws WriteExternalException {
+    super.writeExternal(element);
+    DefaultJDOMExternalizer.writeExternal(this, element);
+  }
+
+  public PsiExpression getChildValueExpression(DebuggerTreeNode node, DebuggerContext context) throws EvaluateException {
+    FieldDescriptor fieldDescriptor = (FieldDescriptor)node.getDescriptor();
+
+    PsiElementFactory elementFactory = JavaPsiFacade.getInstance(node.getProject()).getElementFactory();
+    try {
+      return elementFactory.createExpressionFromText(fieldDescriptor.getField().name(), DebuggerUtils.findClass(
+        fieldDescriptor.getObject().referenceType().name(), context.getProject(), context.getDebugProcess().getSearchScope())
+      );
+    }
+    catch (IncorrectOperationException e) {
+      throw new EvaluateException(DebuggerBundle.message("error.invalid.field.name", fieldDescriptor.getField().name()), null);
+    }
+  }
+
+  private static boolean valueExpandable(Value value)  {
+    try {
+      if(value instanceof ArrayReference) {
+        return ((ArrayReference)value).length() > 0;
+      }
+      else if(value instanceof ObjectReference) {
+        return ((ObjectReference)value).referenceType().allFields().size() > 0;
+      }
+    }
+    catch (ObjectCollectedException e) {
+      return true;
+    }
+
+    return false;
+  }
+
+  public boolean isExpandable(Value value, EvaluationContext evaluationContext, NodeDescriptor parentDescriptor) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+    return valueExpandable(value);
+  }
+
+  public boolean isApplicable(Type type) {
+    return type instanceof ReferenceType && !(type instanceof ArrayType);
+  }
+
+  public @NonNls String getName() {
+    return "Object";
+  }
+
+  public void setName(String text) {
+    LOG.assertTrue(false);
+  }
+
+  @Nullable
+  public static String getEnumConstantName(final ObjectReference objRef, ClassType classType) {
+    do {
+      if (!classType.isPrepared()) {
+        return null;
+      }
+      classType = classType.superclass();
+      if (classType == null) {
+        return null;
+      }
+    }
+    while (!("java.lang.Enum".equals(classType.name())));
+    //noinspection HardCodedStringLiteral
+    final Field field = classType.fieldByName("name");
+    if (field == null) {
+      return null;
+    }
+    final Value value = objRef.getValue(field);
+    if (!(value instanceof StringReference)) {
+      return null;
+    }
+    return ((StringReference)value).value();
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/CompoundNodeConfigurable.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/CompoundNodeConfigurable.java
new file mode 100644
index 0000000..21425b9
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/CompoundNodeConfigurable.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree.render;
+
+import com.intellij.openapi.options.ConfigurationException;
+import com.intellij.openapi.options.UnnamedConfigurable;
+
+import javax.swing.*;
+import java.awt.*;
+
+public class CompoundNodeConfigurable implements UnnamedConfigurable {
+  private final CompoundNodeRenderer myRenderer;
+
+  private final UnnamedConfigurable myLabelConfigurable;
+  private final UnnamedConfigurable myChildrenConfigurable;
+
+  private final static UnnamedConfigurable NULL_CONFIGURABLE = new UnnamedConfigurable() {
+    public JComponent createComponent() {
+      return new JPanel();
+    }
+
+    public boolean isModified() {
+      return false;
+    }
+
+    public void apply() {}
+    public void reset() {}
+    public void disposeUIResources() {}
+  };
+
+  public CompoundNodeConfigurable(CompoundNodeRenderer renderer,
+                                  UnnamedConfigurable labelConfigurable,
+                                  UnnamedConfigurable childrenConfigurable) {
+    myRenderer = renderer;
+    myLabelConfigurable    = labelConfigurable    != null ? labelConfigurable    : NULL_CONFIGURABLE;
+    myChildrenConfigurable = childrenConfigurable != null ? childrenConfigurable : NULL_CONFIGURABLE;
+  }
+
+  public CompoundNodeRenderer getRenderer() {
+    return myRenderer;
+  }
+
+  public JComponent createComponent() {
+    JPanel panel = new JPanel(new GridBagLayout());
+    GridBagConstraints c = new GridBagConstraints();
+    c.fill = GridBagConstraints.BOTH;
+    c.weightx = 1.0;
+    c.insets = new Insets(0, 0, 5, 0);
+    c.gridwidth = GridBagConstraints.REMAINDER;
+
+    panel.add(myLabelConfigurable.createComponent(), c);
+
+    c.ipady = 1;
+    panel.add(new JSeparator(JSeparator.HORIZONTAL), c);
+
+    c.ipady = 0;
+    c.weighty = 1.0;
+    panel.add(myChildrenConfigurable.createComponent(), c);
+    return panel;
+  }
+
+  public boolean isModified() {
+    return myLabelConfigurable.isModified() || myChildrenConfigurable.isModified();
+  }
+
+  public void apply() throws ConfigurationException {
+    myLabelConfigurable.apply();
+    myChildrenConfigurable.apply();
+  }
+
+  public void reset() {
+    myLabelConfigurable.reset();
+    myChildrenConfigurable.reset();
+  }
+
+  public void disposeUIResources() {
+    myLabelConfigurable.disposeUIResources();
+    myChildrenConfigurable.disposeUIResources();
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/CompoundNodeRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/CompoundNodeRenderer.java
new file mode 100644
index 0000000..99d11ff
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/CompoundNodeRenderer.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree.render;
+
+import com.intellij.debugger.DebuggerContext;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContext;
+import com.intellij.debugger.settings.NodeRendererSettings;
+import com.intellij.debugger.ui.tree.DebuggerTreeNode;
+import com.intellij.debugger.ui.tree.NodeDescriptor;
+import com.intellij.debugger.ui.tree.ValueDescriptor;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.psi.PsiExpression;
+import com.sun.jdi.Type;
+import com.sun.jdi.Value;
+import org.jdom.Element;
+import org.jetbrains.annotations.NonNls;
+
+import java.util.Iterator;
+import java.util.List;
+
+public class CompoundNodeRenderer extends NodeRendererImpl{
+  public static final @NonNls String UNIQUE_ID = "CompoundNodeRenderer";
+
+  private ValueLabelRenderer myLabelRenderer;
+  private ChildrenRenderer myChildrenRenderer;
+  protected final NodeRendererSettings myRendererSettings;
+
+  public CompoundNodeRenderer(NodeRendererSettings rendererSettings, String name, ValueLabelRenderer labelRenderer, ChildrenRenderer childrenRenderer) {
+    myRendererSettings = rendererSettings;
+    setName(name);
+    myLabelRenderer = labelRenderer;
+    myChildrenRenderer = childrenRenderer;
+  }
+
+  public String getUniqueId() {
+    return UNIQUE_ID;
+  }
+
+  public CompoundNodeRenderer clone() {
+    CompoundNodeRenderer renderer = (CompoundNodeRenderer)super.clone();
+    renderer.myLabelRenderer    = (myLabelRenderer    != null) ? (ValueLabelRenderer)myLabelRenderer.clone() : null;
+    renderer.myChildrenRenderer = (myChildrenRenderer != null) ? (ChildrenRenderer)myChildrenRenderer.clone() : null;
+    return renderer;
+  }
+
+  public void buildChildren(Value value, ChildrenBuilder builder, EvaluationContext evaluationContext) {
+    getChildrenRenderer().buildChildren(value, builder, evaluationContext);
+  }
+
+  public PsiExpression getChildValueExpression(DebuggerTreeNode node, DebuggerContext context) throws EvaluateException {
+    return getChildrenRenderer().getChildValueExpression(node, context);
+  }
+
+  public boolean isExpandable(Value value, EvaluationContext evaluationContext, NodeDescriptor parentDescriptor) {
+    return getChildrenRenderer().isExpandable(value, evaluationContext, parentDescriptor);
+  }
+
+  public boolean isApplicable(Type type) {
+    return getLabelRenderer().isApplicable(type) && getChildrenRenderer().isApplicable(type);
+  }
+
+  public String calcLabel(ValueDescriptor descriptor, EvaluationContext evaluationContext, DescriptorLabelListener listener) throws EvaluateException {
+    return getLabelRenderer().calcLabel(descriptor, evaluationContext, listener);
+  }
+
+  public ValueLabelRenderer getLabelRenderer() {
+    return myLabelRenderer;
+  }
+
+  public ChildrenRenderer getChildrenRenderer() {
+    return myChildrenRenderer;
+  }
+
+  public void setLabelRenderer(ValueLabelRenderer labelRenderer) {
+    myLabelRenderer = labelRenderer;
+  }
+
+  public void setChildrenRenderer(ChildrenRenderer childrenRenderer) {
+    myChildrenRenderer = childrenRenderer;
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  public void readExternal(Element element) throws InvalidDataException {
+    super.readExternal(element);
+    final List children = element.getChildren(NodeRendererSettings.RENDERER_TAG);
+    if (children != null) {
+      for (Iterator it = children.iterator(); it.hasNext();) {
+        final Element elem = (Element)it.next();
+        final String role = elem.getAttributeValue("role");
+        if (role == null) {
+          continue;
+        }
+        if ("label".equals(role)) {
+          myLabelRenderer = (ValueLabelRenderer)myRendererSettings.readRenderer(elem);
+        }
+        else if ("children".equals(role)) {
+          myChildrenRenderer = (ChildrenRenderer)myRendererSettings.readRenderer(elem);
+        }
+      }
+    }
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  public void writeExternal(Element element) throws WriteExternalException {
+    super.writeExternal(element);
+    if (myLabelRenderer != null) {
+      final Element labelRendererElement = myRendererSettings.writeRenderer(myLabelRenderer);
+      labelRendererElement.setAttribute("role", "label");
+      element.addContent(labelRendererElement);
+    }
+    if (myChildrenRenderer != null) {
+      final Element childrenRendererElement = myRendererSettings.writeRenderer(myChildrenRenderer);
+      childrenRendererElement.setAttribute("role", "children");
+      element.addContent(childrenRendererElement);
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/CompoundReferenceRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/CompoundReferenceRenderer.java
new file mode 100644
index 0000000..c3e20f6
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/CompoundReferenceRenderer.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree.render;
+
+import com.intellij.debugger.engine.DebuggerUtils;
+import com.intellij.debugger.settings.NodeRendererSettings;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.psi.CommonClassNames;
+import com.sun.jdi.ReferenceType;
+import com.sun.jdi.Type;
+import org.jetbrains.annotations.NotNull;
+
+public class CompoundReferenceRenderer extends CompoundNodeRenderer{
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.tree.render.CompoundReferenceRenderer");
+
+  public CompoundReferenceRenderer(final NodeRendererSettings rendererSettings, String name, ValueLabelRenderer labelRenderer, ChildrenRenderer childrenRenderer) {
+    super(rendererSettings, name, labelRenderer, childrenRenderer);
+    myProperties.setClassName(CommonClassNames.JAVA_LANG_OBJECT);
+    LOG.assertTrue(labelRenderer == null || labelRenderer instanceof ReferenceRenderer);
+    LOG.assertTrue(childrenRenderer == null || childrenRenderer instanceof ReferenceRenderer);
+  }
+
+  public void setLabelRenderer(ValueLabelRenderer labelRenderer) {
+    final ValueLabelRenderer prevRenderer = getLabelRenderer();
+    super.setLabelRenderer(myRendererSettings.isBase(labelRenderer) ? null : labelRenderer);
+    final ValueLabelRenderer currentRenderer = getLabelRenderer();
+    if (prevRenderer != currentRenderer) {
+      if (currentRenderer instanceof ReferenceRenderer) {
+        ((ReferenceRenderer)currentRenderer).setClassName(getClassName());
+      }
+    }
+  }
+
+  public void setChildrenRenderer(ChildrenRenderer childrenRenderer) {
+    final ChildrenRenderer prevRenderer = getChildrenRenderer();
+    super.setChildrenRenderer(myRendererSettings.isBase(childrenRenderer) ? null : childrenRenderer);
+    final ChildrenRenderer currentRenderer = getChildrenRenderer();
+    if (prevRenderer != currentRenderer) {
+      if (currentRenderer instanceof ReferenceRenderer) {
+        ((ReferenceRenderer)currentRenderer).setClassName(getClassName());
+      }
+    }
+  }
+
+  public ChildrenRenderer getChildrenRenderer() {
+    final ChildrenRenderer childrenRenderer = super.getChildrenRenderer();
+    return childrenRenderer != null ? childrenRenderer : getDefaultRenderer();
+  }
+
+  private NodeRenderer getDefaultRenderer() {
+    return getClassName().endsWith("]") ? myRendererSettings.getArrayRenderer() : myRendererSettings.getClassRenderer();
+  }
+
+  public ValueLabelRenderer getLabelRenderer() {
+    final ValueLabelRenderer labelRenderer = super.getLabelRenderer();
+    return labelRenderer != null ? labelRenderer : getDefaultRenderer();
+  }
+
+  private ChildrenRenderer getRawChildrenRenderer() {
+    NodeRenderer classRenderer = getDefaultRenderer();
+    final ChildrenRenderer originalRenderer = super.getChildrenRenderer();
+    return originalRenderer == classRenderer ? null : originalRenderer;
+  }
+
+  private ValueLabelRenderer getRawLabelRenderer() {
+    NodeRenderer classRenderer = getDefaultRenderer();
+    final ValueLabelRenderer originalRenderer = super.getLabelRenderer();
+    return originalRenderer == classRenderer ? null : originalRenderer;
+  }
+
+
+  public boolean isApplicable(Type type) {
+    if(type == null || !(type instanceof ReferenceType) || !DebuggerUtils.instanceOf(type, getClassName())) {
+      return false;
+    }
+    return super.isApplicable(type);
+  }
+
+  public void setClassName(@NotNull String name) {
+    myProperties.setClassName(name);
+    if(getRawLabelRenderer() != null) {
+      final ValueLabelRenderer originalLabelRenderer = super.getLabelRenderer();
+      if (originalLabelRenderer instanceof ReferenceRenderer) {
+        ((ReferenceRenderer)originalLabelRenderer).setClassName(name);
+      }
+    }
+
+    if(getRawChildrenRenderer() != null) {
+      final ChildrenRenderer originalChildrenRenderer = super.getChildrenRenderer();
+      if (originalChildrenRenderer instanceof ReferenceRenderer) {
+        ((ReferenceRenderer)originalChildrenRenderer).setClassName(name);
+      }
+    }
+  }
+
+  public @NotNull String getClassName() {
+    return myProperties.getClassName();
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/DescriptorLabelListener.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/DescriptorLabelListener.java
new file mode 100644
index 0000000..1158d99
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/DescriptorLabelListener.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree.render;
+
+
+
+public interface DescriptorLabelListener {
+  DescriptorLabelListener DUMMY_LISTENER = new DescriptorLabelListener() {
+    public void labelChanged() {
+    }
+  };
+
+  void labelChanged();
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/EnumerationChildrenRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/EnumerationChildrenRenderer.java
new file mode 100644
index 0000000..36878a2
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/EnumerationChildrenRenderer.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree.render;
+
+import com.intellij.debugger.DebuggerContext;
+import com.intellij.debugger.engine.DebuggerUtils;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContext;
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.debugger.impl.descriptors.data.UserExpressionData;
+import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl;
+import com.intellij.debugger.ui.tree.*;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.psi.PsiExpression;
+import com.sun.jdi.Value;
+import org.jdom.Element;
+import org.jetbrains.annotations.NonNls;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * User: lex
+ * Date: Dec 19, 2003
+ * Time: 1:25:15 PM
+ */
+public final class EnumerationChildrenRenderer extends com.intellij.debugger.ui.tree.render.ReferenceRenderer implements ChildrenRenderer{
+  public static final @NonNls String UNIQUE_ID = "EnumerationChildrenRenderer";
+
+  private List<Pair<String, TextWithImports>> myChildren;
+  public static final @NonNls String CHILDREN_EXPRESSION = "ChildrenExpression";
+  public static final @NonNls String CHILD_NAME = "Name";
+
+  public EnumerationChildrenRenderer() {
+    this(new ArrayList<Pair<String, TextWithImports>>());
+  }
+
+  public EnumerationChildrenRenderer(List<Pair<String, TextWithImports>> children) {
+    super();
+    myChildren = children;
+  }
+
+  public String getUniqueId() {
+    return UNIQUE_ID;
+  }
+
+  public EnumerationChildrenRenderer clone() {
+    return (EnumerationChildrenRenderer)super.clone();
+  }
+
+  public void readExternal(Element element) throws InvalidDataException {
+    super.readExternal(element);
+
+    myChildren.clear();
+
+    List<Element> children = element.getChildren(CHILDREN_EXPRESSION);
+    for (Iterator<Element> iterator = children.iterator(); iterator.hasNext();) {
+      Element item = iterator.next();
+
+      String name = item.getAttributeValue(CHILD_NAME);
+      TextWithImports text = DebuggerUtils.getInstance().readTextWithImports((Element) item.getChildren().get(0));
+
+      myChildren.add(new Pair<String, TextWithImports>(name, text));
+    }
+  }
+
+  public void writeExternal(Element element) throws WriteExternalException {
+    super.writeExternal(element);
+
+    for (Iterator<Pair<String, TextWithImports>> iterator = myChildren.iterator(); iterator.hasNext();) {
+      Pair<String, TextWithImports> pair = iterator.next();
+      Element child = new Element(CHILDREN_EXPRESSION);
+      child.setAttribute(CHILD_NAME, pair.getFirst());
+      child.addContent(DebuggerUtils.getInstance().writeTextWithImports(pair.getSecond()));
+
+      element.addContent(child);
+    }
+  }
+
+  public void buildChildren(Value value, ChildrenBuilder builder, EvaluationContext evaluationContext) {
+    NodeManager nodeManager = builder.getNodeManager();
+    NodeDescriptorFactory descriptorFactory = builder.getDescriptorManager();
+
+    List<DebuggerTreeNode> children = new ArrayList<DebuggerTreeNode>();
+    for (Pair<String, TextWithImports> pair : myChildren) {
+      children.add(nodeManager.createNode(descriptorFactory.getUserExpressionDescriptor(
+        builder.getParentDescriptor(),
+        new UserExpressionData((ValueDescriptorImpl)builder.getParentDescriptor(), getClassName(), pair.getFirst(), pair.getSecond())), evaluationContext)
+      );
+    }
+    builder.setChildren(children);
+  }
+
+  public PsiExpression getChildValueExpression(DebuggerTreeNode node, DebuggerContext context) throws EvaluateException {
+    return ((ValueDescriptor) node.getDescriptor()).getDescriptorEvaluation(context);
+  }
+
+  public boolean isExpandable(Value value, EvaluationContext evaluationContext, NodeDescriptor parentDescriptor) {
+    return myChildren.size() > 0;
+  }
+
+  public List<Pair<String, TextWithImports>> getChildren() {
+    return myChildren;
+  }
+
+  public void setChildren(List<Pair<String, TextWithImports>> children) {
+    myChildren = children;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ExpressionChildrenRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ExpressionChildrenRenderer.java
new file mode 100644
index 0000000..b902b5b
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ExpressionChildrenRenderer.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree.render;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerContext;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.DebuggerUtils;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.engine.evaluation.EvaluationContext;
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator;
+import com.intellij.debugger.ui.tree.DebuggerTreeNode;
+import com.intellij.debugger.ui.tree.NodeDescriptor;
+import com.intellij.debugger.ui.tree.NodeManager;
+import com.intellij.debugger.ui.tree.ValueDescriptor;
+import com.intellij.openapi.util.DefaultJDOMExternalizer;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.Key;
+import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.psi.PsiExpression;
+import com.sun.jdi.BooleanValue;
+import com.sun.jdi.Value;
+import org.jdom.Element;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * User: lex
+ * Date: Sep 17, 2003
+ * Time: 2:04:00 PM
+ */
+public class ExpressionChildrenRenderer extends ReferenceRenderer implements ChildrenRenderer {
+  public static final @NonNls String UNIQUE_ID = "ExpressionChildrenRenderer";
+  private static final Key<Value> EXPRESSION_VALUE = new Key<Value>("EXPRESSION_VALUE");
+  private static final Key<NodeRenderer> LAST_CHILDREN_RENDERER = new Key<NodeRenderer>("LAST_CHILDREN_RENDERER");
+
+  private final CachedEvaluator myChildrenExpandable = new CachedEvaluator() {
+    protected String getClassName() {
+      return ExpressionChildrenRenderer.this.getClassName();
+    }
+  };
+
+  private final CachedEvaluator myChildrenExpression = new CachedEvaluator() {
+    protected String getClassName() {
+      return ExpressionChildrenRenderer.this.getClassName();
+    }
+  };
+
+  public String getUniqueId() {
+    return UNIQUE_ID;
+  }
+
+  public ExpressionChildrenRenderer clone() {
+    return (ExpressionChildrenRenderer)super.clone();
+  }
+
+  public void buildChildren(final Value value, final ChildrenBuilder builder, final EvaluationContext evaluationContext) {
+    final NodeManager nodeManager = builder.getNodeManager();
+
+    try {
+      final ValueDescriptor parentDescriptor = builder.getParentDescriptor();
+      final Value childrenValue = evaluateChildren(
+        evaluationContext.createEvaluationContext(value), parentDescriptor
+      );
+
+      NodeRenderer renderer = getLastChildrenRenderer(parentDescriptor);
+      if (renderer == null || childrenValue == null || !renderer.isApplicable(childrenValue.type())) {
+        renderer = DebugProcessImpl.getDefaultRenderer(childrenValue != null ? childrenValue.type() : null);
+        parentDescriptor.putUserData(LAST_CHILDREN_RENDERER, renderer);
+      }
+      renderer.buildChildren(childrenValue, builder, evaluationContext);
+    }
+    catch (final EvaluateException e) {
+      List<DebuggerTreeNode> errorChildren = new ArrayList<DebuggerTreeNode>();
+      errorChildren.add(nodeManager.createMessageNode(DebuggerBundle.message("error.unable.to.evaluate.expression") + " " + e.getMessage()));
+      builder.setChildren(errorChildren);
+    }
+  }
+
+  @Nullable
+  public static NodeRenderer getLastChildrenRenderer(ValueDescriptor descriptor) {
+    return descriptor.getUserData(LAST_CHILDREN_RENDERER);
+  }
+
+  public static void setPreferableChildrenRenderer(ValueDescriptor descriptor, NodeRenderer renderer) {
+    descriptor.putUserData(LAST_CHILDREN_RENDERER, renderer);
+  }
+
+  private Value evaluateChildren(EvaluationContext context, NodeDescriptor descriptor) throws EvaluateException {
+    final ExpressionEvaluator evaluator = myChildrenExpression.getEvaluator(context.getProject());
+
+    Value value = evaluator.evaluate(context);
+    descriptor.putUserData(EXPRESSION_VALUE, value);
+    return value;
+  }
+
+  public void readExternal(Element element) throws InvalidDataException {
+    super.readExternal(element);
+    DefaultJDOMExternalizer.readExternal(this, element);
+
+    TextWithImports childrenExpression = DebuggerUtils.getInstance().readTextWithImports(element, "CHILDREN_EXPRESSION");
+    if(childrenExpression != null) {
+      setChildrenExpression(childrenExpression);
+    }
+
+    TextWithImports childrenExpandable = DebuggerUtils.getInstance().readTextWithImports(element, "CHILDREN_EXPANDABLE");
+    if(childrenExpandable != null) {
+      myChildrenExpandable.setReferenceExpression(childrenExpandable);
+    }
+  }
+
+  public void writeExternal(Element element) throws WriteExternalException {
+    super.writeExternal(element);
+    DefaultJDOMExternalizer.writeExternal(this, element);
+    DebuggerUtils.getInstance().writeTextWithImports(element, "CHILDREN_EXPANDABLE", getChildrenExpandable());
+    DebuggerUtils.getInstance().writeTextWithImports(element, "CHILDREN_EXPRESSION", getChildrenExpression());
+  }
+
+  public PsiExpression getChildValueExpression(DebuggerTreeNode node, DebuggerContext context) throws EvaluateException {
+    ValueDescriptor descriptor = (ValueDescriptor) node.getParent().getDescriptor();
+    Value expressionValue = descriptor.getUserData(EXPRESSION_VALUE);
+    if(expressionValue == null) {
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("error.unable.to.evaluate.expression"));
+    }
+
+    ChildrenRenderer defaultChildrenRenderer = ((DebugProcessImpl)context.getDebugProcess()).getDefaultRenderer(expressionValue.type());
+
+    return DebuggerUtils.getInstance().substituteThis(
+            defaultChildrenRenderer.getChildValueExpression(node, context),
+            (PsiExpression)myChildrenExpression.getPsiExpression(node.getProject()).copy(),
+            expressionValue, context);
+  }
+
+  public boolean isExpandable(Value value, final EvaluationContext context, NodeDescriptor parentDescriptor) {
+    final EvaluationContext evaluationContext = context.createEvaluationContext(value);
+
+    if(!"".equals(myChildrenExpandable.getReferenceExpression().getText())) {
+      try {
+        Value expanded = myChildrenExpandable.getEvaluator(evaluationContext.getProject()).evaluate(evaluationContext);
+        if(expanded instanceof BooleanValue) {
+          return ((BooleanValue)expanded).booleanValue();
+        }
+      }
+      catch (EvaluateException e) {
+        // ignored
+      }
+    }
+
+    try {
+      Value children = evaluateChildren(evaluationContext, parentDescriptor);
+
+      ChildrenRenderer defaultChildrenRenderer = ((DebugProcessImpl)evaluationContext.getDebugProcess()).getDefaultRenderer(value.type());
+
+      return defaultChildrenRenderer.isExpandable(children, evaluationContext, parentDescriptor);
+    }
+    catch (EvaluateException e) {
+      return true;
+    }
+  }
+
+  public TextWithImports getChildrenExpression() {
+    return myChildrenExpression.getReferenceExpression();
+  }
+
+  public void setChildrenExpression(TextWithImports expression) {
+    myChildrenExpression.setReferenceExpression(expression);
+  }
+
+  public TextWithImports getChildrenExpandable() {
+    return myChildrenExpandable.getReferenceExpression();
+  }
+
+  public void setChildrenExpandable(TextWithImports childrenExpandable) {
+    myChildrenExpandable.setReferenceExpression(childrenExpandable);
+  }
+
+  public void setClassName(String name) {
+    super.setClassName(name);
+    myChildrenExpression.clear();
+    myChildrenExpandable.clear();
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/HexRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/HexRenderer.java
new file mode 100644
index 0000000..6af36f0
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/HexRenderer.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree.render;
+
+import com.intellij.debugger.DebuggerContext;
+import com.intellij.debugger.engine.evaluation.EvaluationContext;
+import com.intellij.debugger.ui.tree.DebuggerTreeNode;
+import com.intellij.debugger.ui.tree.NodeDescriptor;
+import com.intellij.debugger.ui.tree.ValueDescriptor;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.psi.PsiExpression;
+import com.sun.jdi.*;
+import org.jetbrains.annotations.NonNls;
+
+/**
+ * User: lex
+ * Date: Nov 19, 2003
+ * Time: 3:13:11 PM
+ */
+public class HexRenderer extends NodeRendererImpl{
+  public static final @NonNls String UNIQUE_ID = "HexRenderer";
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.tree.render.HexRenderer");
+
+  public HexRenderer() {
+    setEnabled(false);
+  }
+
+  public String getUniqueId() {
+    return UNIQUE_ID;
+  }
+
+  public @NonNls String getName() {
+    return "Hex";
+  }
+
+  public void setName(String name) {
+    // prohibit change
+  }
+
+  public HexRenderer clone() {
+    return (HexRenderer) super.clone();
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  public String calcLabel(ValueDescriptor valueDescriptor, EvaluationContext evaluationContext, DescriptorLabelListener labelListener) {
+    Value value = valueDescriptor.getValue();
+    StringBuilder buf = new StringBuilder(16);
+
+    if(value == null) {
+      buf.append("null");
+    }
+    else if (value instanceof CharValue) {
+      buf.append("'");
+      buf.append(value.toString());
+      buf.append("' ");
+      long longValue = ((PrimitiveValue)value).longValue();
+      buf.append("0x").append(Long.toHexString(longValue).toUpperCase());
+    }
+    else if (value instanceof ByteValue) {
+      byte val = ((PrimitiveValue)value).byteValue();
+      String strValue = Integer.toHexString(val).toUpperCase();
+      if (strValue.length() > 2) {
+        strValue = strValue.substring(strValue.length() - 2);
+      }
+      buf.append("0x").append(strValue);
+    }
+    else if (value instanceof ShortValue) {
+      short val = ((PrimitiveValue)value).shortValue();
+      String strValue = Integer.toHexString(val).toUpperCase();
+      if (strValue.length() > 4) {
+        strValue = strValue.substring(strValue.length() - 4);
+      }
+      buf.append("0x").append(strValue);
+    }
+    else if (value instanceof IntegerValue) {
+      int val = ((PrimitiveValue)value).intValue();
+      buf.append("0x").append(Integer.toHexString(val).toUpperCase());
+    }
+    else if (value instanceof LongValue) {
+      long val = ((PrimitiveValue)value).longValue();
+      buf.append("0x").append(Long.toHexString(val).toUpperCase());
+    }
+    else {
+      LOG.assertTrue(false);
+    }
+    return buf.toString();
+  }
+
+  public void buildChildren(Value value, ChildrenBuilder builder, EvaluationContext evaluationContext) {
+  }
+
+  //returns whether this renderer is apllicable to this type or it's supertypes
+  public boolean isApplicable(Type t) {
+    if(t == null) {
+      return false;
+    }
+    return t instanceof CharType ||
+           t instanceof ByteType ||
+           t instanceof ShortType ||
+           t instanceof IntegerType ||
+           t instanceof LongType;
+  }
+
+  public PsiExpression getChildValueExpression(DebuggerTreeNode node, DebuggerContext context) {
+    LOG.assertTrue(false);
+    return null;
+  }
+
+  public boolean isExpandable(Value value, EvaluationContext evaluationContext, NodeDescriptor parentDescriptor) {
+    return false;
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/LabelRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/LabelRenderer.java
new file mode 100644
index 0000000..31a457a
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/LabelRenderer.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree.render;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.DebugProcess;
+import com.intellij.debugger.engine.DebuggerUtils;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.engine.evaluation.EvaluationContext;
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator;
+import com.intellij.debugger.ui.tree.ValueDescriptor;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.DefaultJDOMExternalizer;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.WriteExternalException;
+import com.sun.jdi.PrimitiveValue;
+import com.sun.jdi.Value;
+import org.jdom.Element;
+import org.jetbrains.annotations.NonNls;
+
+import javax.swing.*;
+
+/**
+ * User: lex
+ * Date: Sep 20, 2003
+ * Time: 10:27:12 PM
+ */
+public class LabelRenderer extends com.intellij.debugger.ui.tree.render.ReferenceRenderer implements ValueLabelRenderer{
+  public static final @NonNls String UNIQUE_ID = "LabelRenderer";
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.impl.watch.render.ClassLabelRenderer");
+
+  private final CachedEvaluator myLabelExpression = new CachedEvaluator() {
+    protected String getClassName() {
+      return LabelRenderer.this.getClassName();
+    }
+  };
+
+  public LabelRenderer() {
+    super();
+  }
+
+  public String getUniqueId() {
+    return UNIQUE_ID;
+  }
+
+  public LabelRenderer clone() {
+    return (LabelRenderer)super.clone();
+  }
+
+  public Icon calcValueIcon(ValueDescriptor descriptor, EvaluationContext evaluationContext, DescriptorLabelListener listener) throws EvaluateException {
+    return null;
+  }
+
+  public String calcLabel(ValueDescriptor descriptor, EvaluationContext evaluationContext, DescriptorLabelListener labelListener)
+    throws EvaluateException {
+
+    final Value value = descriptor.getValue();
+    LOG.assertTrue(!(value instanceof PrimitiveValue));
+
+    String result;
+    final DebugProcess debugProcess = evaluationContext.getDebugProcess();
+    if (value != null) {
+      try {
+        final ExpressionEvaluator evaluator = myLabelExpression.getEvaluator(debugProcess.getProject());
+
+        if(!debugProcess.isAttached()) {
+          throw EvaluateExceptionUtil.PROCESS_EXITED;
+        }
+        EvaluationContext thisEvaluationContext = evaluationContext.createEvaluationContext(value);
+        Value labelValue = evaluator.evaluate(thisEvaluationContext);
+        result = DebuggerUtils.convertToPresentationString(DebuggerUtils.getValueAsString(thisEvaluationContext, labelValue));
+      }
+      catch (final EvaluateException ex) {
+        throw new EvaluateException(DebuggerBundle.message("error.unable.to.evaluate.expression") + " " + ex.getMessage(), ex);
+      }
+    }
+    else {
+      //noinspection HardCodedStringLiteral
+      result = "null";
+    }
+    return result;
+  }
+
+  public void readExternal(Element element) throws InvalidDataException {
+    super.readExternal(element);
+    DefaultJDOMExternalizer.readExternal(this, element);
+    TextWithImports labelExpression = DebuggerUtils.getInstance().readTextWithImports(element, "LABEL_EXPRESSION");
+    if (labelExpression != null) {
+      setLabelExpression(labelExpression);
+    }
+  }
+
+  public void writeExternal(Element element) throws WriteExternalException {
+    super.writeExternal(element);
+    DefaultJDOMExternalizer.writeExternal(this, element);
+    DebuggerUtils.getInstance().writeTextWithImports(element, "LABEL_EXPRESSION", getLabelExpression());
+  }
+
+  public TextWithImports getLabelExpression() {
+    return myLabelExpression.getReferenceExpression();
+  }
+
+  public void setLabelExpression(TextWithImports expression) {
+    myLabelExpression.setReferenceExpression(expression);
+  }
+
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/NodeRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/NodeRenderer.java
new file mode 100644
index 0000000..aa7f8d9
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/NodeRenderer.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree.render;
+
+public interface NodeRenderer extends ChildrenRenderer, ValueLabelRenderer {
+  String getName();
+
+  void setName(String text);
+
+  boolean isEnabled();
+
+  void setEnabled(boolean enabled);
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/NodeRendererImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/NodeRendererImpl.java
new file mode 100644
index 0000000..9062fa4
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/NodeRendererImpl.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree.render;
+
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContext;
+import com.intellij.debugger.ui.tree.ValueDescriptor;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.WriteExternalException;
+import org.jdom.Element;
+
+import javax.swing.*;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: Feb 9, 2005
+ */
+public abstract class NodeRendererImpl implements NodeRenderer{
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.tree.render.NodeRendererImpl");
+  protected BasicRendererProperties myProperties = new BasicRendererProperties();
+
+  protected NodeRendererImpl() {
+    //noinspection HardCodedStringLiteral
+    myProperties.setName("unnamed");
+  }
+
+  public String getName() {
+    return myProperties.getName();
+  }
+
+  public void setName(String name) {
+    myProperties.setName(name);
+  }
+
+  public boolean isEnabled() {
+    return myProperties.isEnabled();
+  }
+
+  public void setEnabled(boolean enabled) {
+    myProperties.setEnabled(enabled);
+  }
+
+  public Icon calcValueIcon(ValueDescriptor descriptor, EvaluationContext evaluationContext, DescriptorLabelListener listener) throws EvaluateException {
+    return null;
+  }
+
+  public NodeRendererImpl clone() {
+    try {
+      final NodeRendererImpl cloned = (NodeRendererImpl)super.clone();
+      cloned.myProperties = myProperties.clone();
+      return cloned;
+    }
+    catch (CloneNotSupportedException e) {
+      LOG.error(e);
+    }
+    return null;
+  }
+
+  public void readExternal(Element element) throws InvalidDataException {
+    myProperties.readExternal(element);
+  }
+
+  public void writeExternal(Element element) throws WriteExternalException {
+    myProperties.writeExternal(element);
+  }
+
+  public String toString() {
+    return getName();
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/NodeRendererSettingsListener.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/NodeRendererSettingsListener.java
new file mode 100644
index 0000000..6108778
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/NodeRendererSettingsListener.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree.render;
+
+import java.util.EventListener;
+
+public interface NodeRendererSettingsListener extends EventListener{
+  void renderersChanged();
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/PrimitiveRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/PrimitiveRenderer.java
new file mode 100644
index 0000000..d3e70b0
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/PrimitiveRenderer.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree.render;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerContext;
+import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
+import com.intellij.debugger.engine.DebuggerUtils;
+import com.intellij.debugger.engine.evaluation.EvaluationContext;
+import com.intellij.debugger.ui.tree.DebuggerTreeNode;
+import com.intellij.debugger.ui.tree.NodeDescriptor;
+import com.intellij.debugger.ui.tree.ValueDescriptor;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.psi.PsiExpression;
+import com.sun.jdi.*;
+import org.jetbrains.annotations.NonNls;
+
+/**
+ * User: lex
+ * Date: Sep 18, 2003
+ * Time: 3:07:27 PM
+ */
+public class PrimitiveRenderer extends NodeRendererImpl {
+  public static final @NonNls String UNIQUE_ID = "PrimitiveRenderer";
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.tree.render.PrimitiveRenderer");
+
+  public PrimitiveRenderer() {
+    //noinspection HardCodedStringLiteral
+    myProperties.setName("Primitive");
+  }
+
+  public String getUniqueId() {
+    return UNIQUE_ID;
+  }
+
+  public @NonNls String getName() {
+    return "Primitive";
+  }
+
+  public void setName(String text) {
+    // prohibit name change
+  }
+
+  public final boolean isEnabled() {
+    return true;
+  }
+
+  public void setEnabled(boolean enabled) {
+    // prohibit change
+  }
+
+  public boolean isApplicable(Type type) {
+    return type == null || type instanceof PrimitiveType || type instanceof VoidType;
+  }
+
+  public String calcLabel(ValueDescriptor valueDescriptor, EvaluationContext evaluationContext, DescriptorLabelListener labelListener) {
+    Value value = valueDescriptor.getValue();
+    if(value == null) {
+      //noinspection HardCodedStringLiteral
+      return "null";
+    }
+    else if (value instanceof PrimitiveValue) {
+      StringBuilder buf = new StringBuilder(16);
+      if (value instanceof CharValue) {
+        buf.append("'");
+        buf.append(DebuggerUtils.translateStringValue(value.toString()));
+        buf.append("' ");
+        long longValue = ((PrimitiveValue)value).longValue();
+        buf.append(Long.toString(longValue));
+      }
+      else if (value instanceof ByteValue) {
+        buf.append(value.toString());
+      }
+      else if (value instanceof ShortValue) {
+        buf.append(value.toString());
+      }
+      else if (value instanceof IntegerValue) {
+        buf.append(value.toString());
+      }
+      else if (value instanceof LongValue) {
+        buf.append(value.toString());
+      }
+      else {
+        buf.append(value.toString());
+      }
+      return buf.toString();
+    }
+    else {
+      return DebuggerBundle.message("label.undefined");
+    }
+  }
+
+  public void buildChildren(Value value, ChildrenBuilder builder, EvaluationContext evaluationContext) {
+    DebuggerManagerThreadImpl.assertIsManagerThread();
+  }
+
+  public PsiExpression getChildValueExpression(DebuggerTreeNode node, DebuggerContext context) {
+    LOG.assertTrue(false);
+    return null;
+  }
+
+  public boolean isExpandable(Value value, EvaluationContext evaluationContext, NodeDescriptor parentDescriptor) {
+    return false;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ReferenceRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ReferenceRenderer.java
new file mode 100644
index 0000000..9c664c3
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ReferenceRenderer.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree.render;
+
+import com.intellij.debugger.engine.DebuggerUtils;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.psi.CommonClassNames;
+import com.sun.jdi.ReferenceType;
+import com.sun.jdi.Type;
+import org.jdom.Element;
+import org.jetbrains.annotations.NotNull;
+
+public abstract class ReferenceRenderer implements Renderer {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.tree.render.ReferenceRenderer");
+  protected BasicRendererProperties myProperties = new BasicRendererProperties();
+
+  protected ReferenceRenderer() {
+    this(CommonClassNames.JAVA_LANG_OBJECT);
+  }
+
+  protected ReferenceRenderer(@NotNull String className) {
+    myProperties.setClassName(className);
+  }
+
+  public String getClassName() {
+    return myProperties.getClassName();
+  }
+
+  public void setClassName(String className) {
+    myProperties.setClassName(className);
+  }
+
+  public Renderer clone() {
+    try {
+      final ReferenceRenderer cloned = (ReferenceRenderer)super.clone();
+      cloned.myProperties = myProperties.clone();
+      return cloned;
+    }
+    catch (CloneNotSupportedException e) {
+      LOG.error(e);
+    }
+    return null;
+  }
+
+  public boolean isApplicable(Type type) {
+    return type != null && type instanceof ReferenceType && DebuggerUtils.instanceOf(type, getClassName());
+  }
+
+  public void writeExternal(Element element) throws WriteExternalException {
+    myProperties.writeExternal(element);
+  }
+
+  public void readExternal(Element element) throws InvalidDataException {
+    myProperties.readExternal(element);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/Renderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/Renderer.java
new file mode 100644
index 0000000..3546f18
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/Renderer.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree.render;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.JDOMExternalizable;
+import com.sun.jdi.Type;
+
+public interface Renderer extends Cloneable, JDOMExternalizable {
+
+  String getUniqueId();
+
+  /***
+   * Checks whether this renderer is apllicable to this value
+   * @param type
+   */
+  boolean isApplicable(Type type);
+
+  Renderer clone();
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ToStringCommand.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ToStringCommand.java
new file mode 100644
index 0000000..0493bc5
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ToStringCommand.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree.render;
+
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContext;
+import com.intellij.debugger.engine.DebuggerUtils;
+import com.intellij.debugger.engine.SuspendContext;
+import com.intellij.debugger.engine.managerThread.SuspendContextCommand;
+import com.sun.jdi.Value;
+
+/**
+ * User: lex
+ * Date: Sep 16, 2003
+ * Time: 10:58:26 AM
+ */
+public abstract class ToStringCommand implements SuspendContextCommand {
+  private final EvaluationContext myEvaluationContext;
+  private final Value myValue;
+
+  private boolean myIsEvaluated = false;
+
+  protected ToStringCommand(EvaluationContext evaluationContext, Value value) {
+    myEvaluationContext = evaluationContext;
+    myValue = value;
+  }
+
+  public void action() {
+    if(myIsEvaluated) return;
+    try {
+      final String valueAsString = DebuggerUtils.getValueAsString(myEvaluationContext, myValue);
+      evaluationResult(valueAsString);
+    } 
+    catch(final EvaluateException ex) {
+      evaluationError(ex.getMessage());
+    }
+  }
+
+  public void commandCancelled() {
+  }
+
+  public void setEvaluated() {
+    myIsEvaluated = true;
+  }
+
+  public SuspendContext getSuspendContext() {
+    return myEvaluationContext.getSuspendContext();
+  }
+
+  public abstract void evaluationResult(String message);
+  public abstract void evaluationError (String message);
+
+  public Value getValue() {
+    return myValue;
+  }
+
+  public EvaluationContext getEvaluationContext() {
+    return myEvaluationContext;
+  }
+}
+
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ToStringRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ToStringRenderer.java
new file mode 100644
index 0000000..6a96753
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ToStringRenderer.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree.render;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerContext;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.DebuggerUtils;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContext;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.ui.tree.DebuggerTreeNode;
+import com.intellij.debugger.ui.tree.NodeDescriptor;
+import com.intellij.debugger.ui.tree.ValueDescriptor;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.JDOMExternalizerUtil;
+import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.psi.CommonClassNames;
+import com.intellij.psi.PsiExpression;
+import com.intellij.ui.classFilter.ClassFilter;
+import com.intellij.xdebugger.impl.ui.XDebuggerUIConstants;
+import com.sun.jdi.*;
+import org.jdom.Element;
+import org.jetbrains.annotations.NonNls;
+
+import java.util.Iterator;
+
+public class ToStringRenderer extends NodeRendererImpl {
+  public static final @NonNls String UNIQUE_ID = "ToStringRenderer";
+
+  private boolean USE_CLASS_FILTERS = false;
+  private ClassFilter[] myClassFilters = ClassFilter.EMPTY_ARRAY;
+
+  public ToStringRenderer() {
+    setEnabled(true);
+  }
+
+  public String getUniqueId() {
+    return UNIQUE_ID;
+  }
+
+  public @NonNls String getName() {
+    return "toString";
+  }
+
+  public void setName(String name) {
+    // prohibit change
+  }
+
+  public ToStringRenderer clone() {
+    final ToStringRenderer cloned = (ToStringRenderer)super.clone();
+    final ClassFilter[] classFilters = (myClassFilters.length > 0)? new ClassFilter[myClassFilters.length] : ClassFilter.EMPTY_ARRAY;
+    for (int idx = 0; idx < classFilters.length; idx++) {
+      classFilters[idx] = myClassFilters[idx].clone();
+    }
+    cloned.myClassFilters = classFilters;
+    return cloned;
+  }
+
+  public String calcLabel(final ValueDescriptor valueDescriptor, EvaluationContext evaluationContext, final DescriptorLabelListener labelListener)
+    throws EvaluateException {
+    final Value value = valueDescriptor.getValue();
+    BatchEvaluator.getBatchEvaluator(evaluationContext.getDebugProcess()).invoke(new ToStringCommand(evaluationContext, value) {
+      public void evaluationResult(String message) {
+        valueDescriptor.setValueLabel(
+          message == null? "" : "\"" + DebuggerUtils.convertToPresentationString(DebuggerUtilsEx.truncateString(message)) + "\""
+        );
+        labelListener.labelChanged();
+      }
+
+      public void evaluationError(String message) {
+        final String msg = value != null? message + " " + DebuggerBundle.message("evaluation.error.cannot.evaluate.tostring", value.type().name()) : message;
+        valueDescriptor.setValueLabelFailed(new EvaluateException(msg, null));
+        labelListener.labelChanged();
+      }
+    });
+    return XDebuggerUIConstants.COLLECTING_DATA_MESSAGE;
+  }
+
+  public boolean isUseClassFilters() {
+    return USE_CLASS_FILTERS;
+  }
+
+  public void setUseClassFilters(boolean value) {
+    USE_CLASS_FILTERS = value;
+  }
+
+  public boolean isApplicable(Type type) {
+    if(!(type instanceof ReferenceType)) {
+      return false;
+    }
+
+    if(type.name().equals("java.lang.String")) {
+      return false; // do not render 'String' objects for performance reasons
+    }
+
+    if(!overridesToString(type)) {
+      return false;
+    }
+
+    if (USE_CLASS_FILTERS) {
+      if (!isFiltered(type)) {
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  private static boolean overridesToString(Type type) {
+    if(type instanceof ClassType) {
+      final ClassType classType = (ClassType)type;
+      final java.util.List methods = classType.methodsByName("toString", "()Ljava/lang/String;");
+      if (methods.size() > 0) {
+        for (Iterator iterator = methods.iterator(); iterator.hasNext();) {
+          final Method method = (Method)iterator.next();
+          if(!(method.declaringType().name()).equals(CommonClassNames.JAVA_LANG_OBJECT)){
+            return true;
+          }
+        }
+      }
+    }
+    return false;
+  }
+
+  public void buildChildren(Value value, ChildrenBuilder builder, EvaluationContext evaluationContext) {
+    final DebugProcessImpl debugProcess = (DebugProcessImpl)evaluationContext.getDebugProcess();
+    debugProcess.getDefaultRenderer(value).buildChildren(value, builder, evaluationContext);
+  }
+
+  public PsiExpression getChildValueExpression(DebuggerTreeNode node, DebuggerContext context) throws EvaluateException {
+    final Value parentValue = ((ValueDescriptor)node.getParent().getDescriptor()).getValue();
+    final DebugProcessImpl debugProcess = (DebugProcessImpl)context.getDebugProcess();
+    return debugProcess.getDefaultRenderer(parentValue).getChildValueExpression(node, context);
+  }
+
+  public boolean isExpandable(Value value, EvaluationContext evaluationContext, NodeDescriptor parentDescriptor) {
+    final DebugProcessImpl debugProcess = (DebugProcessImpl)evaluationContext.getDebugProcess();
+    return debugProcess.getDefaultRenderer(value).isExpandable(value, evaluationContext, parentDescriptor);
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  public void readExternal(Element element) throws InvalidDataException {
+    super.readExternal(element);
+    final String value = JDOMExternalizerUtil.readField(element, "USE_CLASS_FILTERS");
+    USE_CLASS_FILTERS = "true".equalsIgnoreCase(value);
+    myClassFilters = DebuggerUtilsEx.readFilters(element.getChildren("filter"));
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  public void writeExternal(Element element) throws WriteExternalException {
+    super.writeExternal(element);
+    JDOMExternalizerUtil.writeField(element, "USE_CLASS_FILTERS", USE_CLASS_FILTERS? "true" : "false");
+    DebuggerUtilsEx.writeFilters(element, "filter", myClassFilters);
+  }
+
+  public ClassFilter[] getClassFilters() {
+    return myClassFilters;
+  }
+
+  public void setClassFilters(ClassFilter[] classFilters) {
+    myClassFilters = classFilters != null? classFilters : ClassFilter.EMPTY_ARRAY;
+  }
+
+  private boolean isFiltered(Type t) {
+    if (t instanceof ReferenceType) {
+      for (ClassFilter classFilter : myClassFilters) {
+        if (classFilter.isEnabled() && DebuggerUtilsEx.getSuperType(t, classFilter.getPattern()) != null) {
+          return true;
+        }
+      }
+    }
+    return DebuggerUtilsEx.isFiltered(t.name(), myClassFilters);
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ValueLabelRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ValueLabelRenderer.java
new file mode 100644
index 0000000..903f103
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ValueLabelRenderer.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree.render;
+
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContext;
+import com.intellij.debugger.ui.tree.ValueDescriptor;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+
+/**
+ * User: lex
+ * Date: Sep 20, 2003
+ * Time: 10:12:39 PM
+ */
+public interface ValueLabelRenderer extends Renderer {
+  String calcLabel(ValueDescriptor descriptor, EvaluationContext evaluationContext, DescriptorLabelListener listener) throws EvaluateException;
+
+  @Nullable
+  Icon calcValueIcon(ValueDescriptor descriptor, EvaluationContext evaluationContext, DescriptorLabelListener listener) throws EvaluateException;
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/configurables/ClassChildrenExpressionConfigurable.form b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/configurables/ClassChildrenExpressionConfigurable.form
new file mode 100644
index 0000000..f592206
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/configurables/ClassChildrenExpressionConfigurable.form
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.debugger.ui.tree.render.configurables.ClassChildrenExpressionConfigurable">
+  <grid id="1ddd" binding="myPanel" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+    <margin top="0" left="0" bottom="0" right="0"/>
+    <constraints>
+      <xy x="38" y="77" width="450" height="138"/>
+      <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3"/>
+    </constraints>
+    <properties/>
+    <border type="none"/>
+    <children>
+      <component id="cb46f" class="com.intellij.openapi.ui.LabeledComponent" binding="myChildrenPanel">
+        <constraints>
+          <xy x="0" y="0" width="450" height="31"/>
+          <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="1" fill="1"/>
+        </constraints>
+        <properties>
+          <componentClass value="javax.swing.JPanel"/>
+          <labelInsets top="0" left="0" bottom="5" right="0"/>
+          <text resource-bundle="messages/DebuggerBundle" key="label.node.descendands.expression"/>
+        </properties>
+      </component>
+      <component id="5dbf7" class="com.intellij.openapi.ui.LabeledComponent" binding="myExpandablePanel">
+        <constraints>
+          <xy x="0" y="36" width="450" height="31"/>
+          <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="1" fill="1"/>
+        </constraints>
+        <properties>
+          <componentClass value="javax.swing.JPanel"/>
+          <labelInsets top="0" left="0" bottom="5" right="0"/>
+          <text resource-bundle="messages/DebuggerBundle" key="node.has.descendands.expression.optional"/>
+        </properties>
+      </component>
+      <vspacer id="2950c">
+        <constraints>
+          <xy x="219" y="67" width="11" height="71"/>
+          <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2"/>
+        </constraints>
+      </vspacer>
+    </children>
+  </grid>
+</form>
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/configurables/ClassChildrenExpressionConfigurable.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/configurables/ClassChildrenExpressionConfigurable.java
new file mode 100644
index 0000000..47faa68
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/configurables/ClassChildrenExpressionConfigurable.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree.render.configurables;
+
+import com.intellij.debugger.engine.DebuggerUtils;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.ui.CompletionEditor;
+import com.intellij.debugger.ui.tree.render.ExpressionChildrenRenderer;
+import com.intellij.openapi.options.ConfigurationException;
+import com.intellij.openapi.options.UnnamedConfigurable;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.LabeledComponent;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.search.GlobalSearchScope;
+
+import javax.swing.*;
+import java.awt.*;
+
+public class ClassChildrenExpressionConfigurable implements UnnamedConfigurable{
+  private final ExpressionChildrenRenderer myRenderer;
+
+  private JPanel myPanel;
+  private LabeledComponent<JPanel> myChildrenPanel;
+  private LabeledComponent<JPanel> myExpandablePanel;
+
+  private final CompletionEditor myChildrenEditor;
+  private final CompletionEditor myExpandableEditor;
+
+  public ClassChildrenExpressionConfigurable(Project project, ExpressionChildrenRenderer renderer) {
+    myRenderer = renderer;
+
+    PsiClass psiClass = DebuggerUtils.findClass(myRenderer.getClassName(), project, GlobalSearchScope.allScope(project));
+    myChildrenEditor   = ((DebuggerUtilsEx)DebuggerUtils.getInstance()).createEditor(project, psiClass, "ClassChildrenExpression");
+    myExpandableEditor = ((DebuggerUtilsEx)DebuggerUtils.getInstance()).createEditor(project, psiClass, "ClassChildrenExpression");
+
+    myChildrenPanel.getComponent().setLayout(new BorderLayout());
+    myChildrenPanel.getComponent().add(myChildrenEditor);
+
+    myExpandablePanel.getComponent().setLayout(new BorderLayout());
+    myExpandablePanel.getComponent().add(myExpandableEditor);    
+  }
+
+  public JComponent createComponent() {
+    return myPanel;
+  }
+
+  public boolean isModified() {
+    return !myRenderer.getChildrenExpression().equals(myChildrenEditor.getText()) ||
+           !myRenderer.getChildrenExpandable().equals(myExpandableEditor.getText());
+  }
+
+  public void apply() throws ConfigurationException {
+    myRenderer.setChildrenExpression(myChildrenEditor.getText());
+    myRenderer.setChildrenExpandable(myExpandableEditor.getText());
+  }
+
+  public void reset() {
+    myChildrenEditor.setText(myRenderer.getChildrenExpression());
+    myExpandableEditor.setText(myRenderer.getChildrenExpandable());
+  }
+
+  public void disposeUIResources() {
+    myChildrenEditor.dispose();
+    myExpandableEditor.dispose();
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/configurables/ClassLabelExpressionConfigurable.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/configurables/ClassLabelExpressionConfigurable.java
new file mode 100644
index 0000000..ac8a7c6
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/configurables/ClassLabelExpressionConfigurable.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree.render.configurables;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.DebuggerUtils;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.ui.CompletionEditor;
+import com.intellij.debugger.ui.tree.render.LabelRenderer;
+import com.intellij.openapi.options.ConfigurationException;
+import com.intellij.openapi.options.UnnamedConfigurable;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.LabeledComponent;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.search.GlobalSearchScope;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import java.awt.*;
+
+public class ClassLabelExpressionConfigurable implements UnnamedConfigurable{
+  private final LabelRenderer myRenderer;
+  private LabeledComponent<CompletionEditor> myCompletionEditor;
+  private final JPanel myPanel;
+
+  public ClassLabelExpressionConfigurable(@NotNull Project project, LabelRenderer renderer) {
+    myRenderer = renderer;
+
+    myCompletionEditor = new LabeledComponent<CompletionEditor>();
+    final PsiClass psiClass = DebuggerUtils.findClass(myRenderer.getClassName(), project, GlobalSearchScope.allScope(project));
+    myCompletionEditor.setComponent(((DebuggerUtilsEx)DebuggerUtils.getInstance()).createEditor(project, psiClass, "ClassLabelExpression"));
+    myCompletionEditor.setText(DebuggerBundle.message("label.class.label.expression.configurable.node.label"));
+
+    myPanel = new JPanel(new BorderLayout());
+    myPanel.add(myCompletionEditor, BorderLayout.NORTH);
+  }
+
+  public JComponent createComponent() {
+    return myPanel;
+  }
+
+  public boolean isModified() {
+    return !myRenderer.getLabelExpression().equals(myCompletionEditor.getComponent().getText());
+  }
+
+  public void apply() throws ConfigurationException {
+    myRenderer.setLabelExpression(myCompletionEditor.getComponent().getText());
+  }
+
+  public void reset() {
+    myCompletionEditor.getComponent().setText(myRenderer.getLabelExpression());
+  }
+
+  public void disposeUIResources() {
+    if (myCompletionEditor != null) {
+      myCompletionEditor.getComponent().dispose();
+      myCompletionEditor = null;
+    }
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/configurables/NamedChildrenConfigurable.form b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/configurables/NamedChildrenConfigurable.form
new file mode 100644
index 0000000..419e226
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/configurables/NamedChildrenConfigurable.form
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.debugger.ui.tree.render.configurables.NamedChildrenConfigurable">
+  <grid id="47245" binding="myPanel" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+    <margin top="0" left="0" bottom="0" right="0"/>
+    <constraints>
+      <xy x="57" y="23" width="298" height="252"/>
+      <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3"/>
+    </constraints>
+    <properties/>
+    <border type="none"/>
+    <children>
+      <component id="a2d2a" class="javax.swing.JLabel" binding="myTableLabel">
+        <constraints>
+          <xy x="0" y="2" width="110" height="16"/>
+          <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0"/>
+        </constraints>
+        <properties>
+          <text resource-bundle="messages/DebuggerBundle" key="label.named.children.configurable.node.descendants"/>
+        </properties>
+      </component>
+      <grid id="c8237" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+        <margin top="0" left="0" bottom="0" right="0"/>
+        <constraints>
+          <xy x="0" y="25" width="298" height="227"/>
+          <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3"/>
+        </constraints>
+        <properties/>
+        <border type="none"/>
+        <children>
+          <scrollpane class="com.intellij.ui.components.JBScrollPane" id="68272">
+            <constraints>
+              <xy x="0" y="0" width="188" height="227"/>
+              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="7" anchor="0" fill="3"/>
+            </constraints>
+            <properties/>
+            <border type="none"/>
+            <children>
+              <component id="8776c" class="com.intellij.util.ui.Table" binding="myTable">
+                <constraints/>
+                <properties>
+                  <preferredScrollableViewportSize width="-1" height="-1"/>
+                </properties>
+              </component>
+            </children>
+          </scrollpane>
+          <grid id="c7716" row-count="5" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+            <margin top="0" left="0" bottom="0" right="0"/>
+            <constraints>
+              <xy x="198" y="0" width="100" height="227"/>
+              <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3"/>
+            </constraints>
+            <properties/>
+            <border type="none"/>
+            <children>
+              <component id="c1f20" class="javax.swing.JButton" binding="myButtonRemove">
+                <constraints>
+                  <xy x="0" y="31" width="100" height="26"/>
+                  <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1"/>
+                </constraints>
+                <properties>
+                  <text resource-bundle="messages/DebuggerBundle" key="button.remove"/>
+                </properties>
+              </component>
+              <component id="f0acb" class="javax.swing.JButton" binding="myButtonUp">
+                <constraints>
+                  <xy x="0" y="62" width="100" height="26"/>
+                  <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1"/>
+                </constraints>
+                <properties>
+                  <text resource-bundle="messages/DebuggerBundle" key="button.move.up"/>
+                </properties>
+              </component>
+              <component id="66bbb" class="javax.swing.JButton" binding="myButtonDown">
+                <constraints>
+                  <xy x="0" y="93" width="100" height="26"/>
+                  <grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1"/>
+                </constraints>
+                <properties>
+                  <text resource-bundle="messages/DebuggerBundle" key="button.move.down"/>
+                </properties>
+              </component>
+              <component id="5579c" class="javax.swing.JButton" binding="myButtonAdd">
+                <constraints>
+                  <xy x="0" y="0" width="100" height="26"/>
+                  <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1"/>
+                </constraints>
+                <properties>
+                  <text resource-bundle="messages/DebuggerBundle" key="button.add"/>
+                </properties>
+              </component>
+              <vspacer id="d11e5">
+                <constraints>
+                  <xy x="44" y="119" width="11" height="108"/>
+                  <grid row="4" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2"/>
+                </constraints>
+              </vspacer>
+            </children>
+          </grid>
+        </children>
+      </grid>
+    </children>
+  </grid>
+</form>
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/configurables/NamedChildrenConfigurable.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/configurables/NamedChildrenConfigurable.java
new file mode 100644
index 0000000..7e1515f
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/configurables/NamedChildrenConfigurable.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree.render.configurables;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.DebuggerUtils;
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
+import com.intellij.debugger.ui.CompletionEditor;
+import com.intellij.debugger.ui.tree.render.EnumerationChildrenRenderer;
+import com.intellij.openapi.options.ConfigurationException;
+import com.intellij.openapi.options.UnnamedConfigurable;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Pair;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.ui.TableUtil;
+import com.intellij.util.ui.AbstractTableCellEditor;
+import com.intellij.util.ui.Table;
+
+import javax.swing.*;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.table.DefaultTableModel;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
+
+public class NamedChildrenConfigurable implements UnnamedConfigurable{
+  private Table myTable;
+  private final EnumerationChildrenRenderer myRenderer;
+  private JPanel myPanel;
+  private JLabel myTableLabel;
+  private JButton myButtonAdd;
+  private JButton myButtonRemove;
+  private JButton myButtonUp;
+  private JButton myButtonDown;
+  private CompletionEditor myCompletionEditor;
+
+  public NamedChildrenConfigurable(Project project, EnumerationChildrenRenderer renderer) {
+    myRenderer = renderer;
+
+    myTableLabel.setLabelFor(myTable);
+
+    getModel().addColumn(DebuggerBundle.message("label.named.children.configurable.table.header.column.name"), (Object[])null);
+    final String expressionColumnName = DebuggerBundle.message("label.named.children.configurable.table.header.column.expression");
+    getModel().addColumn(expressionColumnName, (Object[])null);
+
+    PsiClass psiClass = DebuggerUtils.findClass(myRenderer.getClassName(), project, GlobalSearchScope.allScope(project));
+    myCompletionEditor = ((DebuggerUtilsEx)DebuggerUtils.getInstance()).createEditor(project, psiClass, "NamedChildrenConfigurable");
+
+    myTable.setDragEnabled(false);
+    myTable.setIntercellSpacing(new Dimension(0, 0));
+
+    myTable.getColumn(expressionColumnName).setCellEditor(new AbstractTableCellEditor() {
+      public Object getCellEditorValue() {
+        return myCompletionEditor.getText();
+      }
+
+      public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
+        myCompletionEditor.setText((TextWithImports)value);
+        return myCompletionEditor;
+      }
+    });
+
+    myButtonAdd.addActionListener(new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        getModel().addRow(new Object[] {"", DebuggerUtils.getInstance().createExpressionWithImports("") });
+      }
+    });
+
+    myButtonRemove.addActionListener(new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        int selectedRow = myTable.getSelectedRow();
+        if(selectedRow >= 0 && selectedRow < myTable.getRowCount()) {
+          getModel().removeRow(selectedRow);
+        }
+      }
+    });
+
+    myButtonDown.addActionListener(new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        TableUtil.moveSelectedItemsDown(myTable);
+      }
+    });
+
+    myButtonUp.addActionListener(new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        TableUtil.moveSelectedItemsUp(myTable);
+      }
+    });
+
+    myTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
+      public void valueChanged(ListSelectionEvent e) {
+        updateButtons();
+      }
+    });
+    updateButtons();
+  }
+
+  private void updateButtons() {
+    int selectedRow = myTable.getSelectedRow();
+    myButtonRemove.setEnabled(selectedRow != -1);
+    myButtonUp.setEnabled(selectedRow > 0);
+    myButtonDown.setEnabled(selectedRow < myTable.getRowCount() - 1);
+  }
+
+  private DefaultTableModel getModel() {
+    return ((DefaultTableModel)myTable.getModel());
+  }
+
+  public JComponent createComponent() {
+    return myPanel;
+  }
+
+  public boolean isModified() {
+    return false;
+  }
+
+  public void apply() throws ConfigurationException {
+    DefaultTableModel model = getModel();
+
+    final int size = model.getRowCount();
+    java.util.List<Pair<String, TextWithImports>> result = new ArrayList<Pair<String, TextWithImports>>();
+
+    for (int idx = 0; idx < size; idx++) {
+      result.add(new Pair<String, TextWithImports>((String)model.getValueAt(idx, 0), (TextWithImports)model.getValueAt(idx, 1)));
+    }
+    myRenderer.setChildren(result);
+  }
+
+  public void reset() {
+    while(myTable.getModel().getRowCount() > 0) {
+      getModel().removeRow(0);
+    }
+
+    for (Pair<String, TextWithImports> pair : myRenderer.getChildren()) {
+      getModel().addRow(new Object[]{pair.getFirst(), pair.getSecond()});
+    }
+  }
+
+  public void disposeUIResources() {
+    if (myCompletionEditor != null) {
+      myCompletionEditor.dispose();
+      myCompletionEditor = null;
+    }
+  }
+
+
+  /*
+  private class TextWithImportsTableRenderer implements TableCellRenderer{
+    private final CompletionEditor myEditor;
+
+    private TextWithImportsTableRenderer () {
+      PsiClass psiClass = DebuggerUtils.findClass(myRenderer.getClassName(), myProject);
+      myEditor = DebuggerUtils.getInstance().createEditor(myProject, psiClass, "NamedChildrenConfigurable");
+    }
+
+
+    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+      if(hasFocus) {
+        myEditor.setText((TextWithImports)value);
+        return myEditor;
+      }
+      else {
+        TableCellRenderer defaultRenderer = myTable.getDefaultRenderer(String.class);
+        return defaultRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
+      }
+    }
+  }
+  */
+
+}
diff --git a/java/debugger/openapi/debugger-openapi.iml b/java/debugger/openapi/debugger-openapi.iml
new file mode 100644
index 0000000..52013f3
--- /dev/null
+++ b/java/debugger/openapi/debugger-openapi.iml
@@ -0,0 +1,168 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module relativePaths="true" type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="module" module-name="execution-openapi" />
+    <orderEntry type="module" module-name="jsp-openapi" />
+    <orderEntry type="module" module-name="java-psi-api" />
+    <orderEntry type="module" module-name="resources-en" />
+  </component>
+  <component name="copyright">
+    <Base>
+      <setting name="state" value="0" />
+    </Base>
+    <LanguageOptions name="HTML">
+      <option name="templateOptions">
+        <value>
+          <option name="block" value="true" />
+          <option name="separateBefore" value="false" />
+          <option name="separateAfter" value="false" />
+          <option name="prefixLines" value="true" />
+          <option name="lenBefore" value="80" />
+          <option name="lenAfter" value="80" />
+          <option name="box" value="false" />
+          <option name="filler" value=" " />
+        </value>
+      </option>
+      <option name="notice" value="Copyright (c) &amp;#36;today.year, Your Corporation. All Rights Reserved." />
+      <option name="keyword" value="Copyright" />
+      <option name="fileTypeOverride" value="2" />
+      <option name="relativeBefore" value="true" />
+      <option name="addBlankAfter" value="true" />
+      <option name="fileLocation" value="1" />
+      <option name="useAlternate" value="false" />
+    </LanguageOptions>
+    <LanguageOptions name="JAVA">
+      <option name="templateOptions">
+        <value>
+          <option name="block" value="true" />
+          <option name="separateBefore" value="false" />
+          <option name="separateAfter" value="false" />
+          <option name="prefixLines" value="true" />
+          <option name="lenBefore" value="80" />
+          <option name="lenAfter" value="80" />
+          <option name="box" value="false" />
+          <option name="filler" value=" " />
+        </value>
+      </option>
+      <option name="notice" value="/*&#10; * Copyright 2000-2005 JetBrains s.r.o.&#10; * &#10; * Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);&#10; * you may not use this file except in compliance with the License.&#10; * You may obtain a copy of the License at&#10; * &#10; * http://www.apache.org/licenses/LICENSE-2.0&#10; * &#10; * Unless required by applicable law or agreed to in writing, software&#10; * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,&#10; * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&#10; * See the License for the specific language governing permissions and&#10; * limitations under the License.&#10; */" />
+      <option name="keyword" value="Copyright" />
+      <option name="fileTypeOverride" value="2" />
+      <option name="relativeBefore" value="true" />
+      <option name="addBlankAfter" value="true" />
+      <option name="fileLocation" value="1" />
+      <option name="useAlternate" value="false" />
+    </LanguageOptions>
+    <LanguageOptions name="JSP">
+      <option name="templateOptions">
+        <value>
+          <option name="block" value="true" />
+          <option name="separateBefore" value="false" />
+          <option name="separateAfter" value="false" />
+          <option name="prefixLines" value="true" />
+          <option name="lenBefore" value="80" />
+          <option name="lenAfter" value="80" />
+          <option name="box" value="false" />
+          <option name="filler" value=" " />
+        </value>
+      </option>
+      <option name="notice" value="Copyright (c) &amp;#36;today.year, Your Corporation. All Rights Reserved." />
+      <option name="keyword" value="Copyright" />
+      <option name="fileTypeOverride" value="2" />
+      <option name="relativeBefore" value="true" />
+      <option name="addBlankAfter" value="true" />
+      <option name="fileLocation" value="1" />
+      <option name="useAlternate" value="false" />
+    </LanguageOptions>
+    <LanguageOptions name="JavaScript">
+      <option name="templateOptions">
+        <value>
+          <option name="block" value="true" />
+          <option name="separateBefore" value="false" />
+          <option name="separateAfter" value="false" />
+          <option name="prefixLines" value="true" />
+          <option name="lenBefore" value="80" />
+          <option name="lenAfter" value="80" />
+          <option name="box" value="false" />
+          <option name="filler" value=" " />
+        </value>
+      </option>
+      <option name="notice" value="Copyright (c) &amp;#36;today.year, Your Corporation. All Rights Reserved." />
+      <option name="keyword" value="Copyright" />
+      <option name="fileTypeOverride" value="2" />
+      <option name="relativeBefore" value="true" />
+      <option name="addBlankAfter" value="true" />
+      <option name="fileLocation" value="1" />
+      <option name="useAlternate" value="false" />
+    </LanguageOptions>
+    <LanguageOptions name="Properties">
+      <option name="templateOptions">
+        <value>
+          <option name="block" value="true" />
+          <option name="separateBefore" value="false" />
+          <option name="separateAfter" value="false" />
+          <option name="prefixLines" value="true" />
+          <option name="lenBefore" value="80" />
+          <option name="lenAfter" value="80" />
+          <option name="box" value="false" />
+          <option name="filler" value=" " />
+        </value>
+      </option>
+      <option name="notice" value="Copyright (c) &amp;#36;today.year, Your Corporation. All Rights Reserved." />
+      <option name="keyword" value="Copyright" />
+      <option name="fileTypeOverride" value="2" />
+      <option name="relativeBefore" value="true" />
+      <option name="addBlankAfter" value="true" />
+      <option name="fileLocation" value="1" />
+      <option name="useAlternate" value="false" />
+    </LanguageOptions>
+    <LanguageOptions name="XML">
+      <option name="templateOptions">
+        <value>
+          <option name="block" value="true" />
+          <option name="separateBefore" value="false" />
+          <option name="separateAfter" value="false" />
+          <option name="prefixLines" value="true" />
+          <option name="lenBefore" value="80" />
+          <option name="lenAfter" value="80" />
+          <option name="box" value="false" />
+          <option name="filler" value=" " />
+        </value>
+      </option>
+      <option name="notice" value="Copyright (c) &amp;#36;today.year, Your Corporation. All Rights Reserved." />
+      <option name="keyword" value="Copyright" />
+      <option name="fileTypeOverride" value="2" />
+      <option name="relativeBefore" value="true" />
+      <option name="addBlankAfter" value="true" />
+      <option name="fileLocation" value="1" />
+      <option name="useAlternate" value="false" />
+    </LanguageOptions>
+    <LanguageOptions name="__TEMPLATE__">
+      <option name="templateOptions">
+        <value>
+          <option name="block" value="true" />
+          <option name="separateBefore" value="false" />
+          <option name="separateAfter" value="false" />
+          <option name="prefixLines" value="true" />
+          <option name="lenBefore" value="80" />
+          <option name="lenAfter" value="80" />
+          <option name="box" value="false" />
+          <option name="filler" value=" " />
+        </value>
+      </option>
+      <option name="notice" value="Copyright 2000-&amp;#36;{today.year} JetBrains s.r.o.&#10;&#10;Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);&#10;you may not use this file except in compliance with the License.&#10;You may obtain a copy of the License at&#10;&#10;http://www.apache.org/licenses/LICENSE-2.0&#10;&#10;Unless required by applicable law or agreed to in writing, software&#10;distributed under the License is distributed on an &quot;AS IS&quot; BASIS,&#10;WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&#10;See the License for the specific language governing permissions and&#10;limitations under the License." />
+      <option name="keyword" value="Copyright" />
+      <option name="fileTypeOverride" value="4" />
+      <option name="relativeBefore" value="true" />
+      <option name="addBlankAfter" value="true" />
+      <option name="fileLocation" value="1" />
+      <option name="useAlternate" value="false" />
+    </LanguageOptions>
+  </component>
+</module>
+
diff --git a/java/debugger/openapi/src/com/intellij/debugger/DebuggerBundle.java b/java/debugger/openapi/src/com/intellij/debugger/DebuggerBundle.java
new file mode 100644
index 0000000..179cf4a
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/DebuggerBundle.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2000-2009 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.debugger;
+
+import com.intellij.CommonBundle;
+import com.intellij.execution.configurations.RemoteConnection;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.PropertyKey;
+
+import java.lang.ref.Reference;
+import java.lang.ref.SoftReference;
+import java.util.ResourceBundle;
+
+public class DebuggerBundle {
+  private static Reference<ResourceBundle> ourBundle;
+
+  @NonNls private static final String BUNDLE = "messages.DebuggerBundle";
+
+  private DebuggerBundle() {
+  }
+
+  public static String getAddressDisplayName(final RemoteConnection connection) {
+    return connection.isUseSockets() ? connection.getHostName() + ":" + connection.getAddress() : connection.getAddress();
+  }
+
+  public static String getTransportName(final RemoteConnection connection) {
+    return connection.isUseSockets() ? message("transport.name.socket") : message("transport.name.shared.memory");
+  }
+
+  public static String message(@PropertyKey(resourceBundle = BUNDLE)String key, Object... params) {
+    return CommonBundle.message(getBundle(), key, params);
+  }
+
+  private static ResourceBundle getBundle() {
+    ResourceBundle bundle = null;
+    if (ourBundle != null) bundle = ourBundle.get();
+    if (bundle == null) {
+      bundle = ResourceBundle.getBundle(BUNDLE);
+      ourBundle = new SoftReference<ResourceBundle>(bundle);
+    }
+    return bundle;
+  }
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/DebuggerContext.java b/java/debugger/openapi/src/com/intellij/debugger/DebuggerContext.java
new file mode 100644
index 0000000..d2c9180
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/DebuggerContext.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2000-2009 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.debugger;
+
+import com.intellij.debugger.engine.StackFrameContext;
+import com.intellij.debugger.engine.SuspendContext;
+import com.intellij.openapi.project.Project;
+
+public interface DebuggerContext extends StackFrameContext{
+  SuspendContext getSuspendContext();
+
+  Project getProject();
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/DebuggerManager.java b/java/debugger/openapi/src/com/intellij/debugger/DebuggerManager.java
new file mode 100644
index 0000000..26b02c8
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/DebuggerManager.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2000-2009 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.debugger;
+
+import com.intellij.debugger.engine.DebugProcess;
+import com.intellij.debugger.engine.DebugProcessListener;
+import com.intellij.execution.process.ProcessHandler;
+import com.intellij.openapi.components.ProjectComponent;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.JDOMExternalizable;
+import com.intellij.psi.PsiClass;
+import com.intellij.util.Function;
+
+/**
+ * @author lex
+ */
+public abstract class DebuggerManager implements ProjectComponent, JDOMExternalizable {
+  public static DebuggerManager getInstance(Project project) {
+    return project.getComponent(DebuggerManager.class);
+  }
+
+  public abstract DebugProcess getDebugProcess(ProcessHandler processHandler);
+
+  public abstract void addDebugProcessListener(ProcessHandler processHandler, DebugProcessListener listener);
+
+  public abstract void removeDebugProcessListener(ProcessHandler processHandler, DebugProcessListener listener);
+
+  public abstract boolean isDebuggerManagerThread();
+
+  public abstract void addClassNameMapper(NameMapper mapper);
+
+  public abstract void removeClassNameMapper(NameMapper mapper);
+
+  public abstract String getVMClassQualifiedName(PsiClass aClass);
+
+  /**
+   * @deprecated use PositionManagerFactory extension point instead
+   */
+  public abstract void registerPositionManagerFactory(Function<DebugProcess, PositionManager> factory);
+
+  public abstract void unregisterPositionManagerFactory(Function<DebugProcess, PositionManager> factory);
+
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/NameMapper.java b/java/debugger/openapi/src/com/intellij/debugger/NameMapper.java
new file mode 100644
index 0000000..4530806
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/NameMapper.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2000-2009 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.debugger;
+
+import com.intellij.psi.PsiClass;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Compilers of some java-based languages (like Scala) produce classes with names different from those declared in sources.
+ * If for some language qualified names of compiled classes differ from names declared in the sources, a NameMapper must be registered
+ * within the DebuggerManager class. 
+ * Multiple registered mappers forms a "chain of responsibility" and the first non-null result is returned.  
+ * If no mappers are registered or all mappers returned null, the result of 
+ * PsiClass.getQualifiedName() will be used as a qualified name of the compiled class 
+ */
+public interface NameMapper {
+  /**
+   * @param aClass a top-level class
+   * @return a qualified name of the corresponding compiled class or null if default machanism of getting qualified names must be used  
+   */
+  String getQualifiedName(@NotNull PsiClass aClass);
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/NoDataException.java b/java/debugger/openapi/src/com/intellij/debugger/NoDataException.java
new file mode 100644
index 0000000..b3f30af
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/NoDataException.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2000-2009 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.debugger;
+
+public class NoDataException extends Exception{
+  @Override
+  public Throwable fillInStackTrace() {
+    return this;
+  }
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/PositionManager.java b/java/debugger/openapi/src/com/intellij/debugger/PositionManager.java
new file mode 100644
index 0000000..5713483
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/PositionManager.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2000-2009 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.debugger;
+
+import com.intellij.debugger.requests.ClassPrepareRequestor;
+import com.sun.jdi.Location;
+import com.sun.jdi.ReferenceType;
+import com.sun.jdi.request.ClassPrepareRequest;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+
+/**
+ * Manages the correspondence between source positions and bytecode locations during JVM debugging.
+ * Instances of this class are created by the factory registered via the {@link PositionManagerFactory} extension point.
+ *
+ * @see com.intellij.debugger.engine.JSR45PositionManager
+ */
+public interface PositionManager {
+  /**
+   * Returns the source position corresponding to the specified bytecode location.
+   *
+   * @param location the bytecode location.
+   * @return the corresponding source position.
+   * @throws NoDataException if the location is not in the code managed by this {@code PositionManager}
+   */
+  @Nullable
+  SourcePosition getSourcePosition(@Nullable Location location) throws NoDataException;
+
+  /**
+   * Returns the list of all Java classes corresponding to the specified position in the source code.
+   *
+   * @param classPosition the source position.
+   * @return the list of corresponding Java classes.
+   * @throws NoDataException if the location is not in the code managed by this {@code PositionManager}
+   * @see com.intellij.debugger.engine.jdi.VirtualMachineProxy#classesByName
+   */
+  @NotNull
+  List<ReferenceType> getAllClasses(SourcePosition classPosition) throws NoDataException;
+
+  /**
+   * Returns the list of bytecode locations in a specific class corresponding to the specified position in the source code.
+   *
+   * @param type a Java class (one of the list returned by {@link #getAllClasses}).
+   * @param position the position in the source code.
+   * @return the list of corresponding bytecode locations.
+   * @throws NoDataException if the location is not in the code managed by this {@code PositionManager}
+   * @see ReferenceType#locationsOfLine(int)
+   */
+  @NotNull
+  List<Location> locationsOfLine(ReferenceType type, SourcePosition position) throws NoDataException;
+
+  /**
+   * Called to request the JVM to notify the debugger engine when a class corresponding to a breakpoint location is loaded.
+   * The implementation should calculate the pattern of the class files corresponding to the breakpoint location and call
+   * {@link com.intellij.debugger.requests.RequestManager#createClassPrepareRequest} to create the request.
+   *
+   * @param requestor the object to receive the notification from the JVM.
+   * @param position the location of a breakpoint.
+   * @return the prepare request, or null if the code is managed by this {@code PositionManager} but no class prepare notification is needed
+   * @throws NoDataException if the position is not in the code managed by this {@code PositionManager}
+   */
+  @Nullable
+  ClassPrepareRequest createPrepareRequest(ClassPrepareRequestor requestor, SourcePosition position) throws NoDataException;
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/PositionManagerFactory.java b/java/debugger/openapi/src/com/intellij/debugger/PositionManagerFactory.java
new file mode 100644
index 0000000..e89d423
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/PositionManagerFactory.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2000-2011 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.debugger;
+
+import com.intellij.debugger.engine.DebugProcess;
+import com.intellij.openapi.extensions.ExtensionPointName;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author yole
+ */
+public abstract class PositionManagerFactory {
+  public static final ExtensionPointName<PositionManagerFactory> EP_NAME = ExtensionPointName.create("com.intellij.debugger.positionManagerFactory");
+
+  @Nullable
+  public abstract PositionManager createPositionManager(DebugProcess process);
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/SourcePosition.java b/java/debugger/openapi/src/com/intellij/debugger/SourcePosition.java
new file mode 100644
index 0000000..9028b14
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/SourcePosition.java
@@ -0,0 +1,312 @@
+/*
+ * Copyright 2000-2009 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.debugger;
+
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.fileEditor.FileEditorManager;
+import com.intellij.openapi.fileEditor.OpenFileDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Comparing;
+import com.intellij.openapi.util.Computable;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.pom.Navigatable;
+import com.intellij.psi.*;
+import com.intellij.util.containers.ContainerUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+
+/**
+ * User: lex
+ * Date: Oct 24, 2003
+ * Time: 8:23:06 PM
+ */
+public abstract class SourcePosition implements Navigatable{
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.SourcePosition");
+  @NotNull
+  public abstract PsiFile getFile();
+
+  public abstract PsiElement getElementAt();
+
+  /**
+   * @return a zero-based line number
+   */
+  public abstract int getLine();
+
+  public abstract int getOffset();
+
+  public abstract Editor openEditor(boolean requestFocus);
+
+  private abstract static class SourcePositionCache extends SourcePosition {
+    @NotNull private final PsiFile myFile;
+    private long myModificationStamp = -1L;
+
+    private PsiElement myPsiElement;
+    private Integer myLine;
+    private Integer myOffset;
+
+    public SourcePositionCache(@NotNull PsiFile file) {
+      myFile = file;
+      updateData();
+    }
+
+    @Override
+    @NotNull
+    public PsiFile getFile() {
+      return myFile;
+    }
+
+    @Override
+    public boolean canNavigate() {
+      return getFile().isValid();
+    }
+
+    @Override
+    public boolean canNavigateToSource() {
+      return canNavigate();
+    }
+
+    @Override
+    public void navigate(final boolean requestFocus) {
+      ApplicationManager.getApplication().invokeLater(new Runnable() {
+        @Override
+        public void run() {
+          if (!canNavigate()) {
+            return;
+          }
+          openEditor(requestFocus);
+        }
+      });
+    }
+
+    @Override
+    public Editor openEditor(final boolean requestFocus) {
+      final PsiFile psiFile = getFile();
+      final Project project = psiFile.getProject();
+      if (project.isDisposed()) {
+        return null;
+      }
+      final VirtualFile virtualFile = psiFile.getVirtualFile();
+      if (virtualFile == null || !virtualFile.isValid()) {
+        return null;
+      }
+      final int offset = getOffset();
+      if (offset < 0) {
+        return null;
+      }
+      return FileEditorManager.getInstance(project).openTextEditor(new OpenFileDescriptor(project, virtualFile, offset), requestFocus);
+    }
+
+    private void updateData() {
+      if(dataUpdateNeeded()) {
+        myModificationStamp = myFile.getModificationStamp();
+        myLine = null;
+        myOffset = null;
+        myPsiElement = null;
+      }
+    }
+
+    private boolean dataUpdateNeeded() {
+      if (myModificationStamp != myFile.getModificationStamp()) {
+        return true;
+      }
+      final PsiElement psiElement = myPsiElement;
+      return psiElement != null && !psiElement.isValid();
+    }
+
+    @Override
+    public int getLine() {
+      updateData();
+      if (myLine == null) {
+        myLine = calcLine();
+      }
+      return myLine.intValue();
+    }
+
+    @Override
+    public int getOffset() {
+      updateData();
+      if (myOffset == null) {
+        myOffset = calcOffset();
+      }
+      return myOffset.intValue();
+    }
+
+    @Override
+    public PsiElement getElementAt() {
+      updateData();
+      if (myPsiElement == null) {
+        myPsiElement = calcPsiElement();
+      }
+      return myPsiElement;
+    }
+
+    protected int calcLine() {
+      final PsiFile file = getFile();
+      Document document = null;
+      try {
+        document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file);
+      }
+      catch (Throwable e) {
+        LOG.error(e);
+      }
+      if (document != null) {
+        try {
+          return document.getLineNumber(calcOffset());
+        }
+        catch (IndexOutOfBoundsException e) {
+          // may happen if document has been changed since the this SourcePosition was created
+        }
+      }
+      return -1;
+    }
+
+    protected int calcOffset() {
+      final PsiFile file = getFile();
+      final Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file);
+      if (document != null) {
+        try {
+          return document.getLineStartOffset(calcLine());
+        }
+        catch (IndexOutOfBoundsException e) {
+          // may happen if document has been changed since the this SourcePosition was created
+        }
+      }
+      return -1;
+    }
+
+    @Nullable
+    protected PsiElement calcPsiElement() {
+      PsiFile psiFile = getFile();
+      int lineNumber = getLine();
+      if(lineNumber < 0) {
+        return psiFile;
+      }
+
+      final Document document = PsiDocumentManager.getInstance(psiFile.getProject()).getDocument(psiFile);
+      if (document == null) {
+        return null;
+      }
+      if (lineNumber >= document.getLineCount()) {
+        return psiFile;
+      }
+      int startOffset = document.getLineStartOffset(lineNumber);
+      if(startOffset == -1) {
+        return null;
+      }
+
+      PsiElement rootElement = psiFile;
+
+      List<PsiFile> allFiles = psiFile.getViewProvider().getAllFiles();
+      if (allFiles.size() > 1) { // jsp & gsp
+        PsiClassOwner owner = ContainerUtil.findInstance(allFiles, PsiClassOwner.class);
+        if (owner != null) {
+          PsiClass[] classes = owner.getClasses();
+          if (classes.length == 1 && classes[0]  instanceof SyntheticElement) {
+            rootElement = classes[0];
+          }
+        }
+      }
+
+      PsiElement element;
+      while(true) {
+        final CharSequence charsSequence = document.getCharsSequence();
+        for (; startOffset < charsSequence.length(); startOffset++) {
+          char c = charsSequence.charAt(startOffset);
+          if (c != ' ' && c != '\t') {
+            break;
+          }
+        }
+        element = rootElement.findElementAt(startOffset);
+
+        if(element instanceof PsiComment) {
+          startOffset = element.getTextRange().getEndOffset() + 1;
+        }
+        else{
+          break;
+        }
+      }
+
+      if (element != null && element.getParent() instanceof PsiForStatement) {
+        return ((PsiForStatement)element.getParent()).getInitialization();
+      }
+      return element;
+    }
+  }
+
+  public static SourcePosition createFromLineComputable(final PsiFile file, final Computable<Integer> line) {
+    return new SourcePositionCache(file) {
+      @Override
+      protected int calcLine() {
+        return line.compute();
+      }
+    };
+  }
+
+  public static SourcePosition createFromLine(final PsiFile file, final int line) {
+    return new SourcePositionCache(file) {
+      @Override
+      protected int calcLine() {
+        return line;
+      }
+    };
+  }
+
+  public static SourcePosition createFromOffset(final PsiFile file, final int offset) {
+    return new SourcePositionCache(file) {
+
+      @Override
+      protected int calcOffset() {
+        return offset;
+      }
+    };
+  }
+     
+  public static SourcePosition createFromElement(PsiElement element) {
+    final PsiElement navigationElement = element.getNavigationElement();
+    final PsiFile psiFile;
+    if (JspPsiUtil.isInJspFile(navigationElement)) {
+      psiFile = JspPsiUtil.getJspFile(navigationElement);
+    }
+    else {
+      psiFile = navigationElement.getContainingFile();
+    }
+    return new SourcePositionCache(psiFile) {
+      @Override
+      protected PsiElement calcPsiElement() {
+        return navigationElement;
+      }
+
+      @Override
+      protected int calcOffset() {
+        return navigationElement.getTextOffset();
+      }
+    };
+  }
+
+  public boolean equals(Object o) {
+    if(o instanceof SourcePosition) {
+      SourcePosition sourcePosition = (SourcePosition)o;
+      return Comparing.equal(sourcePosition.getFile(), getFile()) && sourcePosition.getOffset() == getOffset();
+    }
+
+    return false;
+  }
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/DebugProcess.java b/java/debugger/openapi/src/com/intellij/debugger/engine/DebugProcess.java
new file mode 100644
index 0000000..bca8159
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/engine/DebugProcess.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine;
+
+import com.intellij.debugger.PositionManager;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContext;
+import com.intellij.debugger.engine.jdi.VirtualMachineProxy;
+import com.intellij.debugger.engine.managerThread.DebuggerManagerThread;
+import com.intellij.debugger.requests.RequestManager;
+import com.intellij.execution.ExecutionResult;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Key;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.sun.jdi.*;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+
+/**
+ * @author lex
+ */
+public interface DebugProcess {
+  @NonNls String JAVA_STRATUM = "Java";
+
+  <T> T    getUserData(Key<T> key);  
+  <T> void putUserData(Key<T> key, T value);
+
+  Project getProject();
+
+  RequestManager getRequestsManager();
+
+  PositionManager getPositionManager();
+
+  VirtualMachineProxy getVirtualMachineProxy();
+
+  void addDebugProcessListener(DebugProcessListener listener);
+
+  void removeDebugProcessListener(DebugProcessListener listener);
+
+  void appendPositionManager(PositionManager positionManager);
+
+  void waitFor();
+
+  void waitFor(long timeout);
+
+  void stop(boolean forceTerminate);
+
+  ExecutionResult getExecutionResult();
+
+  DebuggerManagerThread getManagerThread();
+
+  Value invokeMethod(EvaluationContext evaluationContext,
+                     ObjectReference objRef,
+                     Method method,
+                     List args) throws EvaluateException;
+
+  /**
+   * Is equivalent to invokeInstanceMethod(evaluationContext, classType, method, args, 0) 
+   */
+  Value invokeMethod(EvaluationContext evaluationContext,
+                     ClassType classType,
+                     Method method,
+                     List args) throws EvaluateException;
+
+  Value invokeInstanceMethod(EvaluationContext evaluationContext, 
+                             ObjectReference objRef, 
+                             Method method, 
+                             List args, 
+                             int invocationOptions) throws EvaluateException;
+
+  ReferenceType findClass(EvaluationContext evaluationContext,
+                          String name,
+                          ClassLoaderReference classLoader) throws EvaluateException;
+
+  ArrayReference newInstance(ArrayType arrayType,
+                             int dimension) throws EvaluateException;
+
+  ObjectReference newInstance(EvaluationContext evaluationContext,
+                              ClassType classType,
+                              Method constructor,
+                              List paramList) throws EvaluateException;
+
+  boolean isAttached();
+
+  boolean isDetached();
+
+  boolean isDetaching();
+
+  /**
+   * @return the search scope used by debugger to find sources corresponding to classes being executed
+   */
+  @NotNull
+  GlobalSearchScope getSearchScope();
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/DebugProcessAdapter.java b/java/debugger/openapi/src/com/intellij/debugger/engine/DebugProcessAdapter.java
new file mode 100644
index 0000000..16c43c2
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/engine/DebugProcessAdapter.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine;
+
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.configurations.RemoteConnection;
+import com.intellij.execution.configurations.RunProfileState;
+import com.sun.jdi.ThreadReference;
+
+public class DebugProcessAdapter implements DebugProcessListener{
+  //executed in manager thread
+  public void connectorIsReady() {
+  }
+
+  //executed in manager thread
+  public void paused(SuspendContext suspendContext) {
+
+  }
+
+  //executed in manager thread
+  public void resumed(SuspendContext suspendContext) {
+
+  }
+
+  //executed in manager thread
+  public void processDetached(DebugProcess process, boolean closedByUser) {
+
+  }
+
+  //executed in manager thread
+  public void processAttached(DebugProcess process) {
+
+  }
+
+  //executed in manager thread
+  public void threadStarted(DebugProcess proc, ThreadReference thread) {
+  }
+
+  //executed in manager thread
+  public void threadStopped(DebugProcess proc, ThreadReference thread) {
+  }
+
+  public void attachException(RunProfileState state, ExecutionException exception, RemoteConnection remoteConnection) {
+
+  }
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/DebugProcessListener.java b/java/debugger/openapi/src/com/intellij/debugger/engine/DebugProcessListener.java
new file mode 100644
index 0000000..e992f25
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/engine/DebugProcessListener.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine;
+
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.configurations.RemoteConnection;
+import com.intellij.execution.configurations.RunProfileState;
+import com.sun.jdi.ThreadReference;
+
+import java.util.EventListener;
+
+
+public interface DebugProcessListener extends EventListener{
+  //executed in manager thread
+  void connectorIsReady();
+
+  //executed in manager thread
+  void paused(SuspendContext suspendContext);
+
+  //executed in manager thread
+  void resumed(SuspendContext suspendContext);
+
+  //executed in manager thread
+  void processDetached(DebugProcess process, boolean closedByUser);
+
+  //executed in manager thread
+  void processAttached(DebugProcess process);
+
+  void attachException(RunProfileState state, ExecutionException exception, RemoteConnection remoteConnection);
+  
+  void threadStarted(DebugProcess proc, ThreadReference thread);
+  
+  void threadStopped(DebugProcess proc, ThreadReference thread);
+}
+
diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/DebuggerUtils.java b/java/debugger/openapi/src/com/intellij/debugger/engine/DebuggerUtils.java
new file mode 100644
index 0000000..418e442
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/engine/DebuggerUtils.java
@@ -0,0 +1,570 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerContext;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.engine.evaluation.EvaluationContext;
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.execution.ExecutionException;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.extensions.Extensions;
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.fileTypes.LanguageFileType;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.LanguageLevelProjectExtension;
+import com.intellij.openapi.util.Key;
+import com.intellij.openapi.util.Ref;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.*;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.tree.IElementType;
+import com.intellij.psi.util.InheritanceUtil;
+import com.intellij.util.IncorrectOperationException;
+import com.intellij.util.StringBuilderSpinAllocator;
+import com.sun.jdi.*;
+import org.jdom.Element;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.*;
+
+public abstract class DebuggerUtils {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.DebuggerUtils");
+  private static final Key<Method> TO_STRING_METHOD_KEY = new Key<Method>("CachedToStringMethod");
+  public static final Set<String> ourPrimitiveTypeNames = new HashSet<String>(Arrays.asList(
+      "byte", "short", "int", "long", "float", "double", "boolean", "char"
+  ));
+
+  public static void cleanupAfterProcessFinish(DebugProcess debugProcess) {
+    debugProcess.putUserData(TO_STRING_METHOD_KEY, null);
+  }
+
+  @NonNls
+  public static String getValueAsString(final EvaluationContext evaluationContext, Value value) throws EvaluateException {
+    try {
+      if (value == null) {
+        return "null";
+      }
+      if (value instanceof StringReference) {
+        return ((StringReference)value).value();
+      }
+      if (isInteger(value)) {
+        long v = ((PrimitiveValue)value).longValue();
+        return String.valueOf(v);
+      }
+      if (isNumeric(value)) {
+        double v = ((PrimitiveValue)value).doubleValue();
+        return String.valueOf(v);
+      }
+      if (value instanceof BooleanValue) {
+        boolean v = ((PrimitiveValue)value).booleanValue();
+        return String.valueOf(v);
+      }
+      if (value instanceof CharValue) {
+        char v = ((PrimitiveValue)value).charValue();
+        return String.valueOf(v);
+      }
+      if (value instanceof ObjectReference) {
+        if (value instanceof ArrayReference) {
+          final StringBuilder builder = new StringBuilder();
+          builder.append("[");
+          for (Iterator<Value> iterator = ((ArrayReference)value).getValues().iterator(); iterator.hasNext();) {
+            final Value element = iterator.next();
+            builder.append(getValueAsString(evaluationContext, element));
+            if (iterator.hasNext()) {
+              builder.append(",");
+            }
+          }
+          builder.append("]");
+          return builder.toString();
+        }
+
+        final ObjectReference objRef = (ObjectReference)value;
+        final DebugProcess debugProcess = evaluationContext.getDebugProcess();
+        Method toStringMethod = debugProcess.getUserData(TO_STRING_METHOD_KEY);
+        if (toStringMethod == null) {
+          try {
+            ReferenceType refType = objRef.virtualMachine().classesByName(CommonClassNames.JAVA_LANG_OBJECT).get(0);
+            toStringMethod = findMethod(refType, "toString", "()Ljava/lang/String;");
+            debugProcess.putUserData(TO_STRING_METHOD_KEY, toStringMethod);
+          }
+          catch (Exception e) {
+            throw EvaluateExceptionUtil.createEvaluateException(
+              DebuggerBundle.message("evaluation.error.cannot.evaluate.tostring", objRef.referenceType().name()));
+          }
+        }
+        if (toStringMethod == null) {
+          throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.cannot.evaluate.tostring", objRef.referenceType().name()));
+        }
+        final StringReference stringReference = (StringReference)debugProcess.invokeInstanceMethod(evaluationContext, objRef, toStringMethod, Collections.emptyList(), 0);
+        return  stringReference == null ? "null" : stringReference.value();
+      }
+      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.unsupported.expression.type"));
+    }
+    catch (ObjectCollectedException e) {
+      throw EvaluateExceptionUtil.OBJECT_WAS_COLLECTED;
+    }
+  }
+
+  public static final int MAX_DISPLAY_LABEL_LENGTH = 1024/*kb*/ *1024 /*bytes*/ / 2; // 1 Mb string
+
+  public static String convertToPresentationString(String str) {
+    if (str.length() > MAX_DISPLAY_LABEL_LENGTH) {
+      str = translateStringValue(str.substring(0, MAX_DISPLAY_LABEL_LENGTH));
+      StringBuilder buf = new StringBuilder();
+      buf.append(str);
+      if (!str.endsWith("...")) {
+        buf.append("...");
+      }
+      return buf.toString();
+    }
+    return translateStringValue(str);
+  }
+
+  @Nullable
+  public static Method findMethod(ReferenceType refType, @NonNls String methodName, @NonNls String methodSignature) {
+    if (refType instanceof ArrayType) {
+      // for array types methodByName() in JDI always returns empty list
+      final Method method = findMethod(refType.virtualMachine().classesByName(CommonClassNames.JAVA_LANG_OBJECT).get(0), methodName, methodSignature);
+      if (method != null) {
+        return method;
+      }
+    }
+
+    Method method = null;
+    if (methodSignature != null) {
+      if (refType instanceof ClassType) {
+        method = ((ClassType)refType).concreteMethodByName(methodName, methodSignature);
+      }
+      if (method == null) {
+        final List<Method> methods = refType.methodsByName(methodName, methodSignature);
+        if (methods.size() > 0) {
+          method = methods.get(0);
+        }
+      }
+    }
+    else {
+      List<Method> methods = null;
+      if (refType instanceof ClassType) {
+        methods = refType.methodsByName(methodName);
+      }
+      if (methods != null && methods.size() > 0) {
+        method = methods.get(0);
+      }
+    }
+    return method;
+  }
+
+  public static boolean isNumeric(Value value) {
+    return value != null &&
+           (isInteger(value) ||
+            value instanceof FloatValue ||
+            value instanceof DoubleValue
+           );
+  }
+
+  public static boolean isInteger(Value value) {
+    return value != null &&
+           (value instanceof ByteValue ||
+            value instanceof ShortValue ||
+            value instanceof LongValue ||
+            value instanceof IntegerValue
+           );
+  }
+
+  public static String translateStringValue(final String str) {
+    int length = str.length();
+    final StringBuilder buffer = StringBuilderSpinAllocator.alloc();
+    try {
+      StringUtil.escapeStringCharacters(length, str, buffer);
+      if (str.length() > length) {
+        buffer.append("...");
+      }
+      return buffer.toString();
+    }
+    finally {
+      StringBuilderSpinAllocator.dispose(buffer);
+    }
+  }
+
+  protected static ArrayClass getArrayClass(String className) {
+    boolean searchBracket = false;
+    int dims = 0;
+    int pos;
+
+    for(pos = className.lastIndexOf(']'); pos >= 0; pos--){
+      char c = className.charAt(pos);
+
+      if (searchBracket) {
+        if (c == '[') {
+          dims++;
+          searchBracket = false;
+        }
+        else if (!Character.isWhitespace(c)) break;
+      }
+      else {
+        if (c == ']') {
+          searchBracket = true;
+        }
+        else if (!Character.isWhitespace(c)) break;
+      }
+    }
+
+    if (searchBracket) return null;
+
+    if(dims == 0) return null;
+
+    return new ArrayClass(className.substring(0, pos + 1), dims);
+  }
+
+  public static boolean instanceOf(String subType, String superType, Project project) {
+    if(project == null) {
+      return subType.equals(superType);
+    }
+
+    ArrayClass nodeClass = getArrayClass(subType);
+    ArrayClass rendererClass = getArrayClass(superType);
+    if (nodeClass == null || rendererClass == null) return false;
+
+    if (nodeClass.dims == rendererClass.dims) {
+      GlobalSearchScope scope = GlobalSearchScope.allScope(project);
+      PsiClass psiNodeClass = JavaPsiFacade.getInstance(project).findClass(nodeClass.className, scope);
+      PsiClass psiRendererClass = JavaPsiFacade.getInstance(project).findClass(rendererClass.className, scope);
+      return InheritanceUtil.isInheritorOrSelf(psiNodeClass, psiRendererClass, true);
+    }
+    else if (nodeClass.dims > rendererClass.dims) {
+      return rendererClass.className.equals(CommonClassNames.JAVA_LANG_OBJECT);
+    }
+    return false;
+  }
+
+  public static Type getSuperType(Type subType, String superType) {
+    if(CommonClassNames.JAVA_LANG_OBJECT.equals(superType)) {
+      List list = subType.virtualMachine().classesByName(CommonClassNames.JAVA_LANG_OBJECT);
+      if(list.size() > 0) {
+        return (ReferenceType)list.get(0);
+      }
+      return null;
+    }
+
+    return getSuperTypeInt(subType, superType);
+  }
+
+  private static Type getSuperTypeInt(Type subType, String superType) {
+    Type result;
+    if (subType == null) {
+      return null;
+    }
+
+    if (subType.name().equals(superType)) {
+      return subType;
+    }
+
+    if (subType instanceof ClassType) {
+      result = getSuperType(((ClassType)subType).superclass(), superType);
+      if (result != null) {
+        return result;
+      }
+
+      List ifaces = ((ClassType)subType).allInterfaces();
+      for (Iterator iterator = ifaces.iterator(); iterator.hasNext();) {
+        InterfaceType interfaceType = (InterfaceType)iterator.next();
+        if (interfaceType.name().equals(superType)) {
+          return interfaceType;
+        }
+      }
+      return null;
+    }
+
+    if (subType instanceof InterfaceType) {
+      List ifaces = ((InterfaceType)subType).superinterfaces();
+      for (Iterator iterator = ifaces.iterator(); iterator.hasNext();) {
+        InterfaceType interfaceType = (InterfaceType)iterator.next();
+        result = getSuperType(interfaceType, superType);
+        if (result != null) {
+          return result;
+        }
+      }
+    }
+    else if (subType instanceof ArrayType) {
+      if (superType.endsWith("[]")) {
+        try {
+          String superTypeItem = superType.substring(0, superType.length() - 2);
+          Type subTypeItem = ((ArrayType)subType).componentType();
+          return instanceOf(subTypeItem, superTypeItem) ? subType : null;
+        }
+        catch (ClassNotLoadedException e) {
+          LOG.debug(e);
+        }
+      }
+    }
+    else if (subType instanceof PrimitiveType) {
+      //noinspection HardCodedStringLiteral
+      if(superType.equals("java.lang.Primitive")) {
+        return subType;
+      }
+    }
+
+    //only for interfaces and arrays
+    if(CommonClassNames.JAVA_LANG_OBJECT.equals(superType)) {
+      List list = subType.virtualMachine().classesByName(CommonClassNames.JAVA_LANG_OBJECT);
+      if(list.size() > 0) {
+        return (ReferenceType)list.get(0);
+      }
+    }
+    return null;
+  }
+
+  public static boolean instanceOf(Type subType, String superType) {
+    return getSuperType(subType, superType) != null;
+  }
+
+  @Nullable
+  public static PsiClass findClass(final String className, Project project, final GlobalSearchScope scope) {
+    ApplicationManager.getApplication().assertReadAccessAllowed();
+    final PsiManager psiManager = PsiManager.getInstance(project);
+    final JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(psiManager.getProject());
+    if (getArrayClass(className) != null) {
+      return javaPsiFacade.getElementFactory().getArrayClass(LanguageLevelProjectExtension.getInstance(psiManager.getProject()).getLanguageLevel());
+    }
+    if(project.isDefault()) {
+      return null;
+    }
+    final String _className = className.replace('$', '.');
+    PsiClass aClass = javaPsiFacade.findClass(_className, scope);
+    if (aClass == null) {
+      if (!_className.equals(className)) {
+        // try original name if it differs from the normalized name
+        aClass = javaPsiFacade.findClass(className, scope);
+      }
+    }
+    if (aClass == null) {
+      final GlobalSearchScope globalScope = GlobalSearchScope.allScope(project);
+      if (!globalScope.equals(scope)) {
+        aClass = javaPsiFacade.findClass(_className, globalScope);
+        if (aClass == null) {
+          if (!_className.equals(className)) {
+            // try original name with global scope if the original differs from the normalized name
+            aClass = javaPsiFacade.findClass(className, globalScope);
+          }
+        }
+      }
+    }
+    return aClass;
+  }
+
+  public static PsiType getType(String className, Project project) {
+    ApplicationManager.getApplication().assertReadAccessAllowed();
+
+    final PsiManager psiManager = PsiManager.getInstance(project);
+    try {
+      if (getArrayClass(className) != null) {
+        return JavaPsiFacade.getInstance(psiManager.getProject()).getElementFactory().createTypeFromText(className, null);
+      }
+      if(project.isDefault()) {
+        return null;
+      }
+      final PsiClass aClass =
+        JavaPsiFacade.getInstance(psiManager.getProject()).findClass(className.replace('$', '.'), GlobalSearchScope.allScope(project));
+      return JavaPsiFacade.getInstance(psiManager.getProject()).getElementFactory().createType(aClass);
+    }
+    catch (IncorrectOperationException e) {
+      LOG.error(e);
+    }
+    return null;
+  }
+
+  public static void checkSyntax(PsiCodeFragment codeFragment) throws EvaluateException {
+    PsiElement[] children = codeFragment.getChildren();
+
+    if(children.length == 0) throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.empty.code.fragment"));
+    for (int i = 0; i < children.length; i++) {
+      PsiElement child = children[i];
+      if(child instanceof PsiErrorElement) {
+        throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", child.getText()));
+      }
+    }
+  }
+
+  public static boolean hasSideEffects(PsiElement element) {
+    return hasSideEffectsOrReferencesMissingVars(element, null);
+  }
+  
+  public static boolean hasSideEffectsOrReferencesMissingVars(PsiElement element, @Nullable final Set<String> visibleLocalVariables) {
+    final Ref<Boolean> rv = new Ref<Boolean>(Boolean.FALSE);
+    element.accept(new JavaRecursiveElementWalkingVisitor() {
+      @Override 
+      public void visitPostfixExpression(final PsiPostfixExpression expression) {
+        rv.set(Boolean.TRUE);
+      }
+
+      @Override 
+      public void visitReferenceExpression(final PsiReferenceExpression expression) {
+        final PsiElement psiElement = expression.resolve();
+        if (psiElement instanceof PsiLocalVariable) {
+          if (visibleLocalVariables != null) {
+            if (!visibleLocalVariables.contains(((PsiLocalVariable)psiElement).getName())) {
+              rv.set(Boolean.TRUE);
+            }
+          }
+        }
+        else if (psiElement instanceof PsiMethod) {
+          rv.set(Boolean.TRUE);
+          //final PsiMethod method = (PsiMethod)psiElement;
+          //if (!isSimpleGetter(method)) {
+          //  rv.set(Boolean.TRUE);
+          //}
+        }
+        if (!rv.get().booleanValue()) {
+          super.visitReferenceExpression(expression);
+        }
+      }
+
+      @Override 
+      public void visitPrefixExpression(final PsiPrefixExpression expression) {
+        final IElementType op = expression.getOperationTokenType();
+        if (JavaTokenType.PLUSPLUS.equals(op) || JavaTokenType.MINUSMINUS.equals(op)) {
+          rv.set(Boolean.TRUE);
+        }
+        else {
+          super.visitPrefixExpression(expression);
+        }
+      }
+
+      @Override 
+      public void visitAssignmentExpression(final PsiAssignmentExpression expression) {
+        rv.set(Boolean.TRUE);
+      }
+
+      @Override 
+      public void visitCallExpression(final PsiCallExpression callExpression) {
+        rv.set(Boolean.TRUE);
+        //final PsiMethod method = callExpression.resolveMethod();
+        //if (method == null || !isSimpleGetter(method)) {
+        //  rv.set(Boolean.TRUE);
+        //}
+        //else {
+        //  super.visitCallExpression(callExpression);
+        //}
+      }
+    });
+    return rv.get().booleanValue();
+  }
+
+  public abstract String findAvailableDebugAddress(boolean useSockets) throws ExecutionException;
+
+  public static boolean isSynthetic(TypeComponent typeComponent) {
+    if (typeComponent == null) {
+      return false;
+    }
+    VirtualMachine machine = typeComponent.virtualMachine();
+    return machine != null && machine.canGetSyntheticAttribute() && typeComponent.isSynthetic();
+  }
+
+  public static boolean isSimpleGetter(PsiMethod method){
+    final PsiCodeBlock body = method.getBody();
+    if(body == null){
+      return false;
+    }
+
+    final PsiStatement[] statements = body.getStatements();
+    if(statements.length != 1){
+      return false;
+    }
+    
+    final PsiStatement statement = statements[0];
+    if(!(statement instanceof PsiReturnStatement)){
+      return false;
+    }
+    
+    final PsiExpression value = ((PsiReturnStatement)statement).getReturnValue();
+    if(!(value instanceof PsiReferenceExpression)){
+      return false;
+    }
+    
+    final PsiReferenceExpression reference = (PsiReferenceExpression)value;
+    final PsiExpression qualifier = reference.getQualifierExpression();
+    //noinspection HardCodedStringLiteral
+    if(qualifier != null && !"this".equals(qualifier.getText())) {
+      return false;
+    }
+    
+    final PsiElement referent = reference.resolve();
+    if(referent == null) {
+      return false;
+    }
+    
+    if(!(referent instanceof PsiField)) {
+      return false;
+    }
+    
+    return ((PsiField)referent).getContainingClass().equals(method.getContainingClass());
+  }
+
+  public static boolean isPrimitiveType(final String typeName) {
+    return ourPrimitiveTypeNames.contains(typeName);
+  }
+
+  protected static class ArrayClass {
+    public String className;
+    public int dims;
+
+    public ArrayClass(String className, int dims) {
+      this.className = className;
+      this.dims = dims;
+    }
+  }
+
+  public static DebuggerUtils getInstance() {
+    return ServiceManager.getService(DebuggerUtils.class);
+  }
+
+  public abstract PsiExpression substituteThis(PsiExpression expressionWithThis, PsiExpression howToEvaluateThis, Value howToEvaluateThisValue, StackFrameContext context) throws EvaluateException;
+
+  public abstract DebuggerContext getDebuggerContext (DataContext context);
+
+  public abstract Element writeTextWithImports(TextWithImports text);
+  public abstract TextWithImports readTextWithImports (Element element);
+
+  public abstract void writeTextWithImports(Element root, @NonNls String name, TextWithImports value);
+  public abstract TextWithImports readTextWithImports (Element root, @NonNls String name);
+
+  public abstract TextWithImports createExpressionWithImports(@NonNls String expression);
+
+  public abstract PsiElement getContextElement(final StackFrameContext context);
+
+  public abstract PsiClass chooseClassDialog(String title, Project project);
+
+  public static boolean supportsJVMDebugging(FileType type) {
+    return type instanceof LanguageFileType && ((LanguageFileType)type).isJVMDebuggingSupported();
+  }
+
+  public static boolean supportsJVMDebugging(PsiFile file) {
+    final JVMDebugProvider[] providers = Extensions.getExtensions(JVMDebugProvider.EP_NAME);
+    for (JVMDebugProvider provider : providers) {
+      if (provider.supportsJVMDebugging(file)) {
+        return true;
+      }
+    }
+    return false;
+  }
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/JSR45PositionManager.java b/java/debugger/openapi/src/com/intellij/debugger/engine/JSR45PositionManager.java
new file mode 100644
index 0000000..1697684
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/engine/JSR45PositionManager.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.NoDataException;
+import com.intellij.debugger.PositionManager;
+import com.intellij.debugger.SourcePosition;
+import com.intellij.debugger.requests.ClassPrepareRequestor;
+import com.intellij.execution.process.ProcessOutputTypes;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.fileTypes.LanguageFileType;
+import com.intellij.openapi.util.Computable;
+import com.intellij.psi.PsiFile;
+import com.sun.jdi.*;
+import com.sun.jdi.request.ClassPrepareRequest;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: May 23, 2006
+ */
+public abstract class JSR45PositionManager<Scope> implements PositionManager {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.JSR45PositionManager");
+  protected final DebugProcess      myDebugProcess;
+  protected final Scope myScope;
+  private final String myStratumId;
+  protected final SourcesFinder<Scope> mySourcesFinder;
+  protected final String GENERATED_CLASS_PATTERN;
+  protected Matcher myGeneratedClassPatternMatcher;
+  private final Set<LanguageFileType> myFileTypes;
+
+  public JSR45PositionManager(DebugProcess debugProcess, Scope scope, final String stratumId, final LanguageFileType[] acceptedFileTypes,
+                              final SourcesFinder<Scope> sourcesFinder) {
+    myDebugProcess = debugProcess;
+    myScope = scope;
+    myStratumId = stratumId;
+    myFileTypes = Collections.unmodifiableSet(new HashSet<LanguageFileType>(Arrays.asList(acceptedFileTypes)));
+    mySourcesFinder = sourcesFinder;
+    String generatedClassPattern = getGeneratedClassesPackage();
+    if(generatedClassPattern.length() == 0) {
+      generatedClassPattern = getGeneratedClassesNamePattern();
+    }
+    else {
+      generatedClassPattern = generatedClassPattern + "." + getGeneratedClassesNamePattern();
+    }
+    GENERATED_CLASS_PATTERN = generatedClassPattern;
+    myGeneratedClassPatternMatcher = Pattern.compile(generatedClassPattern.replaceAll("\\*", ".*")).matcher("");
+  }
+
+  @NonNls
+  protected abstract String getGeneratedClassesPackage();
+
+  protected String getGeneratedClassesNamePattern() {
+    return "*";
+  }
+
+  public final String getStratumId() {
+    return myStratumId;
+  }
+
+  public SourcePosition getSourcePosition(final Location location) throws NoDataException {
+    SourcePosition sourcePosition = null;
+
+    try {
+      String sourcePath = getRelativeSourcePathByLocation(location);
+      PsiFile file = mySourcesFinder.findSourceFile(sourcePath, myDebugProcess.getProject(), myScope);
+      if(file != null) {
+        int lineNumber = getLineNumber(location);
+        sourcePosition = SourcePosition.createFromLine(file, lineNumber - 1);
+      }
+    }
+    catch (AbsentInformationException ignored) { // ignored
+    }
+    catch (Throwable e) {
+      LOG.info(e);
+    }
+    if(sourcePosition == null) {
+      throw new NoDataException();
+    }
+    return sourcePosition;
+  }
+
+  protected String getRelativeSourcePathByLocation(final Location location) throws AbsentInformationException {
+    return getRelativePath(location.sourcePath(myStratumId));
+  }
+
+  protected int getLineNumber(final Location location) {
+    return location.lineNumber(myStratumId);
+  }
+
+  @NotNull
+  public List<ReferenceType> getAllClasses(SourcePosition classPosition) throws NoDataException {
+    checkSourcePositionFileType(classPosition);
+
+    final List<ReferenceType> referenceTypes = myDebugProcess.getVirtualMachineProxy().allClasses();
+
+    final List<ReferenceType> result = new ArrayList<ReferenceType>();
+
+    for (final ReferenceType referenceType : referenceTypes) {
+      myGeneratedClassPatternMatcher.reset(referenceType.name());
+      if (myGeneratedClassPatternMatcher.matches()) {
+        final List<Location> locations = locationsOfClassAt(referenceType, classPosition);
+        if (locations != null && locations.size() > 0) {
+          result.add(referenceType);
+        }
+      }
+    }
+
+    return result;
+  }
+
+  private void checkSourcePositionFileType(final SourcePosition classPosition) throws NoDataException {
+    final FileType fileType = classPosition.getFile().getFileType();
+    if(!myFileTypes.contains(fileType)) {
+      throw new NoDataException();
+    }
+  }
+
+  @NotNull
+  public List<Location> locationsOfLine(final ReferenceType type, final SourcePosition position) throws NoDataException {
+    List<Location> locations = locationsOfClassAt(type, position);
+    return locations != null ? locations : Collections.<Location>emptyList();
+
+  }
+
+  private List<Location> locationsOfClassAt(final ReferenceType type, final SourcePosition position) throws NoDataException {
+    checkSourcePositionFileType(position);
+
+    return ApplicationManager.getApplication().runReadAction(new Computable<List<Location>>() {
+      public List<Location> compute() {
+        try {
+          final List<String> relativePaths = getRelativeSourePathsByType(type);
+          for (String relativePath : relativePaths) {
+            final PsiFile file = mySourcesFinder.findSourceFile(relativePath, myDebugProcess.getProject(), myScope);
+            if(file != null && file.equals(position.getFile())) {
+              return getLocationsOfLine(type, getSourceName(file.getName(), type), relativePath, position.getLine() + 1);
+            }
+          }
+        }
+        catch(ObjectCollectedException ignored) {
+        }
+        catch(AbsentInformationException ignored) {
+        }
+        catch(ClassNotPreparedException ignored) {                                                                                                           
+        }
+        catch (InternalError e) {
+          myDebugProcess.getExecutionResult().getProcessHandler().notifyTextAvailable(
+            DebuggerBundle.message("internal.error.locations.of.line", type.name()), ProcessOutputTypes.SYSTEM);
+        }
+        return null;
+      }
+
+      // Finds exact server file name (from available in type)
+      // This is needed because some servers (e.g. WebSphere) put not exact file name such as 'A.jsp  '
+      private String getSourceName(final String name, final ReferenceType type) throws AbsentInformationException {
+        for(String sourceNameFromType: type.sourceNames(myStratumId)) {
+          if (sourceNameFromType.indexOf(name) >= 0) {
+            return sourceNameFromType;
+          }
+        }
+        return name;
+      }
+    });
+  }
+
+  protected List<String> getRelativeSourePathsByType(final ReferenceType type) throws AbsentInformationException {
+    final List<String> paths = type.sourcePaths(myStratumId);
+    final ArrayList<String> relativePaths = new ArrayList<String>();
+    for (String path : paths) {
+      relativePaths.add(getRelativePath(path));
+    }
+    return relativePaths;
+  }
+
+  protected List<Location> getLocationsOfLine(final ReferenceType type, final String fileName,
+                                              final String relativePath, final int lineNumber) throws AbsentInformationException {
+    return type.locationsOfLine(myStratumId, fileName, lineNumber);
+  }
+
+  public ClassPrepareRequest createPrepareRequest(final ClassPrepareRequestor requestor, final SourcePosition position)
+    throws NoDataException {
+    checkSourcePositionFileType(position);
+
+    return myDebugProcess.getRequestsManager().createClassPrepareRequest(new ClassPrepareRequestor() {
+      public void processClassPrepare(DebugProcess debuggerProcess, ReferenceType referenceType) {
+        onClassPrepare(debuggerProcess, referenceType, position, requestor);
+      }
+    }, GENERATED_CLASS_PATTERN);
+  }
+
+  protected void onClassPrepare(final DebugProcess debuggerProcess, final ReferenceType referenceType,
+                              final SourcePosition position, final ClassPrepareRequestor requestor) {
+    try {
+      if(locationsOfClassAt(referenceType, position) != null) {
+        requestor.processClassPrepare(debuggerProcess, referenceType);
+      }
+    }
+    catch (NoDataException e) {
+    }
+  }
+
+  protected String getRelativePath(String sourcePath) {
+
+    if (sourcePath != null) {
+      sourcePath = sourcePath.trim();
+      String generatedClassesPackage = getGeneratedClassesPackage();
+      final String prefix = generatedClassesPackage.replace('.', File.separatorChar);
+
+      if (sourcePath.startsWith(prefix)) {
+        sourcePath = sourcePath.substring(prefix.length());
+        if (sourcePath.startsWith(File.separator)) {
+          sourcePath = sourcePath.substring(1);
+        }
+      }
+    }
+
+    return sourcePath;
+  }
+
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/JVMDebugProvider.java b/java/debugger/openapi/src/com/intellij/debugger/engine/JVMDebugProvider.java
new file mode 100644
index 0000000..15fde83
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/engine/JVMDebugProvider.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2000-2010 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.debugger.engine;
+
+import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.psi.PsiFile;
+
+/**
+ * @author Dennis.Ushakov
+ */
+public interface JVMDebugProvider {
+  ExtensionPointName<JVMDebugProvider> EP_NAME = ExtensionPointName.create("com.intellij.debugger.jvmDebugProvider");
+
+  boolean supportsJVMDebugging(PsiFile file);
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/SourcesFinder.java b/java/debugger/openapi/src/com/intellij/debugger/engine/SourcesFinder.java
new file mode 100644
index 0000000..106499b
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/engine/SourcesFinder.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiFile;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: May 23, 2006
+ */
+public interface SourcesFinder<Scope> {
+  /**
+   * Searches for source file within the deployedModules
+   * @param relPath relative path of the source to be found (fetched from the class file)
+   * @param project
+   * @param scope a search scope
+   */
+  @Nullable
+  PsiFile findSourceFile(String relPath, Project project, Scope scope);
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/StackFrameContext.java b/java/debugger/openapi/src/com/intellij/debugger/engine/StackFrameContext.java
new file mode 100644
index 0000000..442f2c7
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/engine/StackFrameContext.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine;
+
+import com.intellij.debugger.engine.jdi.StackFrameProxy;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: lex
+ * Date: Jun 3, 2003
+ * Time: 5:58:58 PM
+ * To change this template use Options | File Templates.
+ */
+public interface StackFrameContext {
+  @Nullable
+  StackFrameProxy  getFrameProxy();
+  DebugProcess     getDebugProcess();
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/SuspendContext.java b/java/debugger/openapi/src/com/intellij/debugger/engine/SuspendContext.java
new file mode 100644
index 0000000..ae89344
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/engine/SuspendContext.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine;
+
+import com.intellij.debugger.engine.jdi.ThreadReferenceProxy;
+
+public interface SuspendContext extends StackFrameContext {
+  public int getSuspendPolicy();
+
+  ThreadReferenceProxy getThread();
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/TopLevelParentClassProvider.java b/java/debugger/openapi/src/com/intellij/debugger/engine/TopLevelParentClassProvider.java
new file mode 100644
index 0000000..782bf34
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/engine/TopLevelParentClassProvider.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2000-2011 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.debugger.engine;
+
+import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.util.PsiTreeUtil;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author Max Medvedev
+ */
+public abstract class TopLevelParentClassProvider {
+  private static final ExtensionPointName<TopLevelParentClassProvider> EP_NAME =
+    ExtensionPointName.create("com.intellij.topLevelClassProvider");
+
+  public static PsiClass getTopLevelParentClass(PsiClass psiClass) {
+    for (TopLevelParentClassProvider provider : EP_NAME.getExtensions()) {
+      final PsiClass custom = provider.getCustomTopLevelParentClass(psiClass);
+      if (custom != null) return custom;
+    }
+
+    PsiClass enclosing = PsiTreeUtil.getParentOfType(psiClass, PsiClass.class, true);
+    while (enclosing != null) {
+      psiClass = enclosing;
+      enclosing = PsiTreeUtil.getParentOfType(enclosing, PsiClass.class, true);
+    }
+    return psiClass;
+  }
+
+  @Nullable
+  protected abstract PsiClass getCustomTopLevelParentClass(PsiClass psiClass);
+
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/CodeFragmentFactory.java b/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/CodeFragmentFactory.java
new file mode 100644
index 0000000..f7ceafc
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/CodeFragmentFactory.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.evaluation;
+
+import com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilder;
+import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.openapi.fileTypes.LanguageFileType;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.JavaCodeFragment;
+import com.intellij.psi.PsiElement;
+
+public abstract class CodeFragmentFactory {
+  public static final ExtensionPointName<CodeFragmentFactory> EXTENSION_POINT_NAME = ExtensionPointName.create("com.intellij.debugger.codeFragmentFactory");
+
+  public abstract JavaCodeFragment createCodeFragment(TextWithImports item, PsiElement context, Project project);
+
+  public abstract JavaCodeFragment createPresentationCodeFragment(TextWithImports item, PsiElement context, Project project);
+
+  public abstract boolean isContextAccepted(PsiElement contextElement);
+
+  public abstract LanguageFileType getFileType();
+
+  /**
+   * In case if createCodeFragment returns java code use
+   * com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilderImpl#getInstance()
+   * @return builder, which can evaluate expression for your code fragment
+   */
+  public abstract EvaluatorBuilder getEvaluatorBuilder();
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/CodeFragmentKind.java b/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/CodeFragmentKind.java
new file mode 100644
index 0000000..34766d2
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/CodeFragmentKind.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.evaluation;
+public enum CodeFragmentKind {
+  EXPRESSION, CODE_BLOCK
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/EvaluateException.java b/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/EvaluateException.java
new file mode 100644
index 0000000..30dac08
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/EvaluateException.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.evaluation;
+
+import com.intellij.openapi.diagnostic.Logger;
+import com.sun.jdi.InvocationException;
+import com.sun.jdi.ObjectReference;
+import org.jetbrains.annotations.Nullable;
+
+public class EvaluateException extends Exception {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.evaluation.EvaluateException");
+  private ObjectReference myTargetException;
+
+  public EvaluateException(final String message) {
+    super(message);
+    if (LOG.isDebugEnabled()) {
+      LOG.debug(message);
+    }
+  }
+
+  public EvaluateException(String msg, Throwable th) {
+    super(msg, th);
+    if (th instanceof EvaluateException) {
+      myTargetException = ((EvaluateException)th).getExceptionFromTargetVM();
+    }
+    else if(th instanceof InvocationException){
+      InvocationException invocationException = (InvocationException) th;
+      myTargetException = invocationException.exception();
+    }
+    if (LOG.isDebugEnabled()) {
+      LOG.debug(msg);
+    }
+  }
+  
+  @Nullable
+  public ObjectReference getExceptionFromTargetVM() {
+    return myTargetException;
+  }
+
+  public void setTargetException(final ObjectReference targetException) {
+    myTargetException = targetException;
+  }
+
+  public String getMessage() {
+    final String errorMessage = super.getMessage();
+    if (errorMessage != null) {
+      return errorMessage;
+    }
+    final Throwable cause = getCause();
+    final String causeMessage = cause != null? cause.getMessage() : null;
+    if (causeMessage != null) {
+      return causeMessage;
+    }
+    return "unknown error";
+  }
+}
\ No newline at end of file
diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/EvaluateExceptionUtil.java b/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/EvaluateExceptionUtil.java
new file mode 100644
index 0000000..4d5536c
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/EvaluateExceptionUtil.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.evaluation;
+
+import com.intellij.debugger.DebuggerBundle;
+import com.sun.jdi.*;
+
+/**
+ * @author lex
+ */
+public class EvaluateExceptionUtil {
+  public static final EvaluateException INCONSISTEND_DEBUG_INFO = createEvaluateException(DebuggerBundle.message("evaluation.error.inconsistent.debug.info"));
+  public static final EvaluateException BOOLEAN_EXPECTED = createEvaluateException(DebuggerBundle.message("evaluation.error.boolean.value.expected.in.condition"));
+  public static final EvaluateException PROCESS_EXITED = createEvaluateException(DebuggerBundle.message("evaluation.error.process.exited"));
+  public static final EvaluateException NULL_STACK_FRAME = createEvaluateException(DebuggerBundle.message("evaluation.error.stack.frame.unavailable"));
+  public static final EvaluateException NESTED_EVALUATION_ERROR = createEvaluateException(DebuggerBundle.message("evaluation.error.nested.evaluation"));
+  public static final EvaluateException INVALID_DEBUG_INFO = createEvaluateException(DebuggerBundle.message("evaluation.error.sources.out.of.sync"));
+  public static final EvaluateException CANNOT_FIND_SOURCE_CLASS = createEvaluateException(DebuggerBundle.message("evaluation.error.cannot.find.stackframe.source"));
+  public static final EvaluateException OBJECT_WAS_COLLECTED = createEvaluateException(DebuggerBundle.message("evaluation.error.object.collected"));
+  public static final EvaluateException ARRAY_WAS_COLLECTED = createEvaluateException(DebuggerBundle.message("evaluation.error.array.collected"));
+  public static final EvaluateException THREAD_WAS_RESUMED = createEvaluateException(DebuggerBundle.message("evaluation.error.thread.resumed"));
+  public static final EvaluateException DEBUG_INFO_UNAVAILABLE = createEvaluateException(DebuggerBundle.message("evaluation.error.debug.info.unavailable"));
+
+  private EvaluateExceptionUtil() {
+  }
+
+  public static EvaluateException createEvaluateException(Throwable th) {
+    return createEvaluateException(null, th);
+  }
+
+  public static EvaluateException createEvaluateException(String msg, Throwable th) {
+    final String message = msg != null? msg + ": " + reason(th) : reason(th);
+    return new EvaluateException(message, th instanceof EvaluateException ? th.getCause() : th);
+  }
+
+  public static EvaluateException createEvaluateException(String reason) {
+    return new EvaluateException(reason, null);
+  }
+
+  private static String reason(Throwable th) {
+    if(th instanceof InvalidTypeException) {
+      final String originalReason = th.getMessage();
+      return DebuggerBundle.message("evaluation.error.type.mismatch") + (originalReason != null? " " + originalReason : "");
+    }
+    else if(th instanceof AbsentInformationException) {
+      return DebuggerBundle.message("evaluation.error.debug.info.unavailable");
+    }
+    else if(th instanceof ClassNotLoadedException) {
+      return DebuggerBundle.message("evaluation.error.class.not.loaded", ((ClassNotLoadedException)th).className());
+    }
+    else if(th instanceof ClassNotPreparedException) {
+      return th.getMessage();
+    }
+    else if(th instanceof IncompatibleThreadStateException) {
+      return DebuggerBundle.message("evaluation.error.thread.not.at.breakpoint");
+    }
+    else if(th instanceof InconsistentDebugInfoException) {
+      return DebuggerBundle.message("evaluation.error.inconsistent.debug.info");
+    }
+    else if(th instanceof ObjectCollectedException) {
+      return DebuggerBundle.message("evaluation.error.object.collected");
+    }
+    else if(th instanceof InvocationException){
+      InvocationException invocationException = (InvocationException) th;
+      return DebuggerBundle.message("evaluation.error.method.exception", invocationException.exception().referenceType().name());
+    }
+    else if(th instanceof EvaluateException) {
+      return th.getMessage();
+    }
+    else {
+      return th.getClass().getName() + " : " + (th.getMessage() != null ? th.getMessage() : "");
+    }
+  }
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/EvaluationContext.java b/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/EvaluationContext.java
new file mode 100644
index 0000000..e50ef43
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/EvaluationContext.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.evaluation;
+
+import com.intellij.debugger.engine.DebugProcess;
+import com.intellij.debugger.engine.StackFrameContext;
+import com.intellij.debugger.engine.SuspendContext;
+import com.intellij.openapi.project.Project;
+import com.sun.jdi.ClassLoaderReference;
+import com.sun.jdi.Value;
+
+public interface EvaluationContext extends StackFrameContext{
+  DebugProcess getDebugProcess();
+
+  EvaluationContext createEvaluationContext(Value value);
+
+  SuspendContext getSuspendContext();
+
+  Project getProject();
+
+  ClassLoaderReference getClassLoader() throws EvaluateException;
+
+  Value getThisObject();
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/TextWithImports.java b/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/TextWithImports.java
new file mode 100644
index 0000000..0ae3e64
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/TextWithImports.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.evaluation;
+
+import com.intellij.openapi.fileTypes.FileType;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public interface TextWithImports {
+  String getText();
+
+  void setText(String newText);
+
+  @NotNull
+  String getImports();
+
+  CodeFragmentKind getKind();
+
+  boolean isEmpty();
+
+  String toExternalForm();
+
+  @Nullable
+  FileType getFileType();
+
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/expression/EvaluatorBuilder.java b/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/expression/EvaluatorBuilder.java
new file mode 100644
index 0000000..66bb45a
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/expression/EvaluatorBuilder.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2000-2011 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.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.SourcePosition;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.psi.PsiElement;
+
+/**
+ * Main interface to extend evaluation for different JVM languages.
+ * @see com.intellij.debugger.engine.evaluation.CodeFragmentFactory
+ */
+public interface EvaluatorBuilder {
+  ExpressionEvaluator build(PsiElement codeFragment, final SourcePosition position) throws EvaluateException;
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/expression/ExpressionEvaluator.java b/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/expression/ExpressionEvaluator.java
new file mode 100644
index 0000000..18528c2
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/expression/ExpressionEvaluator.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContext;
+import com.sun.jdi.Value;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: lex
+ * Date: Jul 15, 2003
+ * Time: 1:44:35 PM
+ * To change this template use Options | File Templates.
+ */
+public interface ExpressionEvaluator {
+  //call evaluate before
+  public Value getValue();
+
+  //call evaluate before
+  public Modifier getModifier();
+
+  public Value evaluate(final EvaluationContext context) throws EvaluateException;
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/expression/Modifier.java b/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/expression/Modifier.java
new file mode 100644
index 0000000..809feac
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/expression/Modifier.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2000-2009 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.
+ */
+
+/*
+ * Interface Modifier
+ * @author Jeka
+ */
+package com.intellij.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.ui.tree.NodeDescriptor;
+import com.intellij.openapi.project.Project;
+import com.sun.jdi.ClassNotLoadedException;
+import com.sun.jdi.InvalidTypeException;
+import com.sun.jdi.Type;
+import com.sun.jdi.Value;
+
+public interface Modifier {
+  boolean canInspect();
+
+  boolean canSetValue();
+  /**
+   * sets the value to the expression
+   */
+  void setValue(Value value) throws ClassNotLoadedException, InvalidTypeException, EvaluateException;
+
+  /**
+   * @return the expected type of the expression or null is class was not loaded
+   */
+  Type getExpectedType() throws ClassNotLoadedException, EvaluateException;
+
+  NodeDescriptor getInspectItem(Project project);
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/jdi/LocalVariableProxy.java b/java/debugger/openapi/src/com/intellij/debugger/engine/jdi/LocalVariableProxy.java
new file mode 100644
index 0000000..8efdaae
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/engine/jdi/LocalVariableProxy.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.jdi;
+
+public interface LocalVariableProxy extends ObjectReferenceProxy{
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/jdi/ObjectReferenceProxy.java b/java/debugger/openapi/src/com/intellij/debugger/engine/jdi/ObjectReferenceProxy.java
new file mode 100644
index 0000000..3ec95fb
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/engine/jdi/ObjectReferenceProxy.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.jdi;
+
+public interface ObjectReferenceProxy {
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/jdi/StackFrameProxy.java b/java/debugger/openapi/src/com/intellij/debugger/engine/jdi/StackFrameProxy.java
new file mode 100644
index 0000000..7e0b6ee
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/engine/jdi/StackFrameProxy.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.jdi;
+
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.sun.jdi.ClassLoaderReference;
+import com.sun.jdi.Location;
+import com.sun.jdi.StackFrame;
+
+public interface StackFrameProxy extends ObjectReferenceProxy{
+  StackFrame getStackFrame() throws EvaluateException;
+
+  int getFrameIndex() throws EvaluateException ;
+
+  VirtualMachineProxy getVirtualMachine();
+
+  Location location() throws EvaluateException;
+
+  ClassLoaderReference getClassLoader() throws EvaluateException;
+
+  LocalVariableProxy visibleVariableByName(String name) throws EvaluateException;
+
+  ThreadReferenceProxy threadProxy();
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/jdi/ThreadGroupReferenceProxy.java b/java/debugger/openapi/src/com/intellij/debugger/engine/jdi/ThreadGroupReferenceProxy.java
new file mode 100644
index 0000000..146ab75
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/engine/jdi/ThreadGroupReferenceProxy.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.jdi;
+
+import com.sun.jdi.ThreadGroupReference;
+
+public interface ThreadGroupReferenceProxy extends ObjectReferenceProxy{
+  ThreadGroupReference getThreadGroupReference();
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/jdi/ThreadReferenceProxy.java b/java/debugger/openapi/src/com/intellij/debugger/engine/jdi/ThreadReferenceProxy.java
new file mode 100644
index 0000000..9723516
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/engine/jdi/ThreadReferenceProxy.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.jdi;
+
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.sun.jdi.ThreadReference;
+
+public interface ThreadReferenceProxy extends ObjectReferenceProxy{
+  VirtualMachineProxy getVirtualMachine();
+  ThreadReference     getThreadReference();
+
+  StackFrameProxy frame(int i) throws EvaluateException;
+
+  int frameCount() throws EvaluateException;
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/jdi/VirtualMachineProxy.java b/java/debugger/openapi/src/com/intellij/debugger/engine/jdi/VirtualMachineProxy.java
new file mode 100644
index 0000000..4f4cb82
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/engine/jdi/VirtualMachineProxy.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.jdi;
+
+import com.intellij.debugger.engine.DebugProcess;
+import com.sun.jdi.ReferenceType;
+
+import java.util.List;
+
+/**
+ * @author lex
+ */
+public interface VirtualMachineProxy {
+  List<ReferenceType> allClasses();
+
+  boolean versionHigher(String version);
+
+  boolean canWatchFieldModification();
+
+  boolean canWatchFieldAccess();
+
+  boolean canInvokeMethods();
+
+  DebugProcess getDebugProcess();
+
+  List<ReferenceType> nestedTypes(ReferenceType refType);
+
+  List<ReferenceType> classesByName(String s);
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/managerThread/DebuggerCommand.java b/java/debugger/openapi/src/com/intellij/debugger/engine/managerThread/DebuggerCommand.java
new file mode 100644
index 0000000..a39d83f
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/engine/managerThread/DebuggerCommand.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.managerThread;
+
+public interface DebuggerCommand {
+  void action();
+
+  void commandCancelled();
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/managerThread/DebuggerManagerThread.java b/java/debugger/openapi/src/com/intellij/debugger/engine/managerThread/DebuggerManagerThread.java
new file mode 100644
index 0000000..8d19667
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/engine/managerThread/DebuggerManagerThread.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.managerThread;
+
+public interface DebuggerManagerThread {
+  /**
+   * executes command in DebuggerManagerThread
+   *
+   * @param command
+   */
+  void invokeCommand(DebuggerCommand command);
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/managerThread/SuspendContextCommand.java b/java/debugger/openapi/src/com/intellij/debugger/engine/managerThread/SuspendContextCommand.java
new file mode 100644
index 0000000..13d75fe
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/engine/managerThread/SuspendContextCommand.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2000-2009 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.debugger.engine.managerThread;
+
+import com.intellij.debugger.engine.SuspendContext;
+
+public interface SuspendContextCommand extends DebuggerCommand{
+  SuspendContext getSuspendContext();
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/package.html b/java/debugger/openapi/src/com/intellij/debugger/package.html
new file mode 100644
index 0000000..e9fa628
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/package.html
@@ -0,0 +1,27 @@
+<!--
+  ~ Copyright 2000-2007 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.
+  -->
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html><body bgcolor="white">
+Provides interfaces for interacting with IDEA's debugger. The main extensibility
+point of the debugger is the possibility for a plugin to provide custom mapping of
+positions in compiled classes to source code lines, which is mostly necessary for
+JSP debugging. Such mapping is provided through the {@link PositionManager} interface.
+One standard implementation of this interface for application servers compatible
+with the JSR-45 specification is provided by the {@link JSR45PositionManager} class.
+Another implementation of this interface, which can be used as an example for the debugger
+API, is found in the Tomcat plugin.
+</body></html>
diff --git a/java/debugger/openapi/src/com/intellij/debugger/requests/ClassPrepareRequestor.java b/java/debugger/openapi/src/com/intellij/debugger/requests/ClassPrepareRequestor.java
new file mode 100644
index 0000000..e58e052
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/requests/ClassPrepareRequestor.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2000-2009 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.debugger.requests;
+
+import com.intellij.debugger.engine.DebugProcess;
+import com.sun.jdi.ReferenceType;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: lex
+ * Date: Jun 27, 2003
+ * Time: 7:27:41 PM
+ * To change this template use Options | File Templates.
+ */
+public interface ClassPrepareRequestor extends Requestor {
+  void processClassPrepare(DebugProcess debuggerProcess, final ReferenceType referenceType);
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/requests/RequestManager.java b/java/debugger/openapi/src/com/intellij/debugger/requests/RequestManager.java
new file mode 100644
index 0000000..bd949fd
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/requests/RequestManager.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2000-2009 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.debugger.requests;
+
+import com.intellij.debugger.SourcePosition;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.sun.jdi.request.ClassPrepareRequest;
+import com.sun.jdi.request.EventRequest;
+
+public interface RequestManager {
+  void callbackOnPrepareClasses(ClassPrepareRequestor requestor, String classOrPatternToBeLoaded);
+  void callbackOnPrepareClasses(ClassPrepareRequestor requestor, SourcePosition classPosition) throws EvaluateException;
+
+  ClassPrepareRequest createClassPrepareRequest(ClassPrepareRequestor requestor, String pattern);  
+
+  void enableRequest(EventRequest request);
+
+  void setInvalid(Requestor requestor, String message);
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/requests/Requestor.java b/java/debugger/openapi/src/com/intellij/debugger/requests/Requestor.java
new file mode 100644
index 0000000..9a13832
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/requests/Requestor.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2000-2009 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.debugger.requests;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: lex
+ * Date: Jun 27, 2003
+ * Time: 8:06:36 PM
+ * To change this template use Options | File Templates.
+ */
+public interface Requestor {
+}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/ui/tree/NodeDescriptor.java b/java/debugger/openapi/src/com/intellij/debugger/ui/tree/NodeDescriptor.java
new file mode 100644
index 0000000..4ed6de6
--- /dev/null
+++ b/java/debugger/openapi/src/com/intellij/debugger/ui/tree/NodeDescriptor.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2000-2009 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.debugger.ui.tree;
+
+import com.intellij.openapi.util.Key;
+
+public interface NodeDescriptor {
+
+  String getName();
+  String getLabel();
+
+  <T> T getUserData(Key<T> key);
+  <T> void putUserData(Key<T> key, T value);
+
+  void displayAs(NodeDescriptor descriptor);
+
+  void setAncestor(NodeDescriptor oldDescriptor);
+}