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

import com.intellij.execution.process.ProcessHandler;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.openapi.wm.ToolWindowType;
import com.intellij.openapi.wm.ex.ToolWindowManagerAdapter;
import com.intellij.openapi.wm.ex.ToolWindowManagerEx;
import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentFactory;
import com.intellij.ui.tabs.TabInfo;
import com.intellij.ui.tabs.impl.JBEditorTabs;
import com.intellij.xdebugger.XDebuggerManager;
import com.jetbrains.python.debugger.PyDebugProcess;
import com.jetbrains.python.debugger.PyDebugValue;
import com.jetbrains.python.debugger.PyFrameAccessor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class PyDataView implements DumbAware {
  public static final String DATA_VIEWER_ID = "Data View";
  public static final String COLORED_BY_DEFAULT = "python.debugger.dataview.coloredbydefault";
  public static final String EMPTY_TAB_NAME = "empty";
  private static final Logger LOG = Logger.getInstance(PyDataView.class);

  @NotNull private final Project myProject;
  private JBEditorTabs myTabs;

  public PyDataView(@NotNull Project project) {
    myProject = project;
  }

  public void show(@NotNull PyDebugValue value) {
    ToolWindow window = ToolWindowManager.getInstance(myProject).getToolWindow(DATA_VIEWER_ID);
    if (window == null) {
      LOG.error("Tool window '" + DATA_VIEWER_ID + "' is not found");
      return;
    }
    window.getContentManager().getReady(this).doWhenDone(() -> {
      TabInfo selectedInfo = addTab(value.getFrameAccessor());
      PyDataViewerPanel dataViewerPanel = (PyDataViewerPanel)selectedInfo.getComponent();
      dataViewerPanel.apply(value);
    });
    window.show(null);
  }

  public void closeRelatedTabs(@NotNull PyDebugProcess process) {
    List<TabInfo> tabsToRemove = new ArrayList<>();
    for (TabInfo info : myTabs.getTabs()) {
      PyFrameAccessor frameAccessor = getPanel(info).getFrameAccessor();
      if (frameAccessor instanceof PyDebugProcess) {
        if (frameAccessor == process) {
          tabsToRemove.add(info);
        }
      }
    }
    ApplicationManager.getApplication().invokeLater(() -> {
      for (TabInfo info : tabsToRemove) {
        myTabs.removeTab(info);
      }
    });
  }

  public void updateTabs(@NotNull ProcessHandler handler) {
    for (TabInfo info : myTabs.getTabs()) {
      PyDataViewerPanel panel = getPanel(info);
      PyFrameAccessor accessor = panel.getFrameAccessor();
      if (!(accessor instanceof PyDebugProcess)) {
        continue;
      }
      boolean shouldBeShown = Comparing.equal(handler, ((PyDebugProcess)accessor).getProcessHandler());
      info.setHidden(!shouldBeShown);
    }
    if (myTabs.getSelectedInfo() == null) {
      PyFrameAccessor accessor = getFrameAccessor(handler);
      if (accessor != null) {
        addTab(accessor);
      }
    }
  }

  @Nullable
  private PyFrameAccessor getFrameAccessor(@NotNull ProcessHandler handler) {
    for (PyDebugProcess process : XDebuggerManager.getInstance(myProject).getDebugProcesses(PyDebugProcess.class)) {
      if (Comparing.equal(handler, process.getProcessHandler())) {
        return process;<commit_msg>select the same tab when switching back (PY-22411)<commit_after>/*
 * Copyright 2000-2017 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.jetbrains.python.debugger.containerview;

import com.intellij.execution.process.ProcessHandler;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.openapi.wm.ToolWindowType;
import com.intellij.openapi.wm.ex.ToolWindowManagerAdapter;
import com.intellij.openapi.wm.ex.ToolWindowManagerEx;
import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentFactory;
import com.intellij.ui.tabs.TabInfo;
import com.intellij.ui.tabs.impl.JBEditorTabs;
import com.intellij.xdebugger.XDebuggerManager;
import com.jetbrains.python.debugger.PyDebugProcess;
import com.jetbrains.python.debugger.PyDebugValue;
import com.jetbrains.python.debugger.PyFrameAccessor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

public class PyDataView implements DumbAware {
  public static final String DATA_VIEWER_ID = "Data View";
  public static final String COLORED_BY_DEFAULT = "python.debugger.dataview.coloredbydefault";
  public static final String EMPTY_TAB_NAME = "empty";
  private static final Logger LOG = Logger.getInstance(PyDataView.class);

  @NotNull private final Project myProject;
  private JBEditorTabs myTabs;
  private final Map<ProcessHandler, TabInfo> mySelectedInfos = new ConcurrentHashMap<>();

  public PyDataView(@NotNull Project project) {
    myProject = project;
  }

  public void show(@NotNull PyDebugValue value) {
    ToolWindow window = ToolWindowManager.getInstance(myProject).getToolWindow(DATA_VIEWER_ID);
    if (window == null) {
      LOG.error("Tool window '" + DATA_VIEWER_ID + "' is not found");
      return;
    }
    window.getContentManager().getReady(this).doWhenDone(() -> {
      TabInfo selectedInfo = addTab(value.getFrameAccessor());
      PyDataViewerPanel dataViewerPanel = (PyDataViewerPanel)selectedInfo.getComponent();
      dataViewerPanel.apply(value);
    });
    window.show(null);
  }

  public void closeRelatedTabs(@NotNull PyDebugProcess process) {
    List<TabInfo> tabsToRemove = new ArrayList<>();
    for (TabInfo info : myTabs.getTabs()) {
      PyFrameAccessor frameAccessor = getPanel(info).getFrameAccessor();
      if (frameAccessor instanceof PyDebugProcess) {
        if (frameAccessor == process) {
          tabsToRemove.add(info);
        }
      }
    }
    ApplicationManager.getApplication().invokeLater(() -> {
      for (TabInfo info : tabsToRemove) {
        myTabs.removeTab(info);
      }
    });
  }

  public void updateTabs(@NotNull ProcessHandler handler) {
    saveSelectedInfo();
    for (TabInfo info : myTabs.getTabs()) {
      PyDataViewerPanel panel = getPanel(info);
      PyFrameAccessor accessor = panel.getFrameAccessor();
      if (!(accessor instanceof PyDebugProcess)) {
        continue;
      }
      boolean shouldBeShown = Comparing.equal(handler, ((PyDebugProcess)accessor).getProcessHandler());
      info.setHidden(!shouldBeShown);
    }
    restoreSelectedInfo(handler);
    if (myTabs.getSelectedInfo() == null) {
      PyFrameAccessor accessor = getFrameAccessor(handler);
      if (accessor != null) {
        addTab(accessor);
      }
    }
  }

  private void restoreSelectedInfo(@NotNull ProcessHandler handler) {
    TabInfo savedSelection = mySelectedInfos.get(handler);
    if (savedSelection != null) {
      myTabs.select(savedSelection, true);
      mySelectedInfos.remove(handler);
    }
  }

  private void saveSelectedInfo() {
    TabInfo selectedInfo = myTabs.getSelectedInfo();
    if (!hasOnlyEmptyTab() && selectedInfo != null) {
      PyFrameAccessor accessor = getPanel(selectedInfo).getFrameAccessor();
      if (accessor instanceof PyDebugProcess) {
        mySelectedInfos.put(((PyDebugProcess)accessor).getProcessHandler(), selectedInfo);
      }
    }
  }

  @Nullable
  private PyFrameAccessor getFrameAccessor(@NotNull ProcessHandler handler) {
    for (PyDebugProcess process : XDebuggerManager.getInstance(myProject).getDebugProcesses(PyDebugProcess.class)) {
      if (Comparing.equal(handler, process.getProcessHandler())) {
        return process;
{'fraction_non_alphanumeric': 0.10147316369630163, 'fraction_numerical': 0.0029875347687236017, 'mean_word_length': 4.3517089305402425, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '830529', 'n_tokens_mistral': 2870, 'n_tokens_neox': 2804, 'n_words': 632}