move scientific mode and SciView toolwindow to pro only

This commit is contained in:
Ekaterina Tuzova
2017-10-06 13:41:30 +03:00
parent 8f51a4c178
commit e2e2f4ae17
15 changed files with 136 additions and 1202 deletions
+2 -19
View File
@@ -46,7 +46,7 @@
<annotator language="Python" implementationClass="com.jetbrains.python.validation.PyAnnotatingVisitor"/>
<annotator language="Python" implementationClass="com.jetbrains.python.validation.PyDumbAwareAnnotator"/>
<annotator language="Python" implementationClass="com.jetbrains.python.inspections.PyCompatibilityInspectionAdvertiser"/>
<annotator language="Python" implementationClass="com.jetbrains.python.inspections.PySciViewAdvertiser"/>
<quoteHandler fileType="Python" className="com.jetbrains.python.editor.PythonQuoteHandler"/>
<enterHandlerDelegate implementation="com.jetbrains.python.editor.PythonEnterHandler"/>
<enterHandlerDelegate implementation="com.jetbrains.python.editor.PyEnterAtIndentHandler" order="first"/>
@@ -624,16 +624,14 @@
<breadcrumbsInfoProvider implementation="com.jetbrains.python.breadcrumbs.PyBreadcrumbsInfoProvider"/>
<highlightVisitor implementation="com.jetbrains.python.highlighting.PyRainbowVisitor"/>
<toolWindow id="SciView" factoryClass="com.jetbrains.python.debugger.containerview.PyDataViewToolWindowFactory" anchor="right" icon="PythonIcons.Python.DataView"/>
<projectService serviceInterface="com.jetbrains.python.debugger.containerview.PyDataView" serviceImplementation="com.jetbrains.python.debugger.containerview.PyDataView"/>
<projectService serviceInterface="com.jetbrains.python.plots.PyPlotToolWindow" serviceImplementation="com.jetbrains.python.plots.PyPlotToolWindow"/>
<createFromTemplateHandler implementation="com.jetbrains.python.packaging.setupPy.PyCreateSetupPyFromTemplateHandler"/>
<consoleHistoryModelProvider implementation="com.jetbrains.python.console.PyConsoleHistoryModelProvider"/>
</extensions>
<extensionPoints>
<extensionPoint qualifiedName="Pythonid.pythonDocumentationQuickInfoProvider" interface="com.jetbrains.python.documentation.PythonDocumentationQuickInfoProvider"/>
<extensionPoint qualifiedName="Pythonid.pythonCommandLineEnvironmentProvider" interface="com.jetbrains.python.run.PythonCommandLineEnvironmentProvider"/>
<extensionPoint qualifiedName="Pythonid.importResolver" interface="com.jetbrains.python.psi.impl.PyImportResolver"/>
<extensionPoint qualifiedName="Pythonid.magicLiteral" interface="com.jetbrains.python.magicLiteral.PyMagicLiteralExtensionPoint"/>
<extensionPoint qualifiedName="Pythonid.unresolvedReferenceSkipper" interface="com.jetbrains.python.inspections.unresolvedReference.PyUnresolvedReferenceSkipperExtPoint"/>
@@ -881,10 +879,6 @@
<add-to-group group-id="DebugMainMenu" relative-to-action="ForceRunToCursor" anchor="after"/>
<add-to-group group-id="EditorPopupMenuDebug" relative-to-action="ForceRunToCursor" anchor="after"/>
</action>
<action id="PySciView" class="com.jetbrains.python.actions.PySciViewAction">
<add-to-group group-id="ViewMenu" anchor="before" relative-to-action="ToggleFullScreenGroup"/>
</action>
</actions>
<extensions defaultExtensionNs="com.intellij.spellchecker">
@@ -892,17 +886,6 @@
<bundledDictionaryProvider implementation="com.jetbrains.python.spellchecker.PythonBundledDictionaryProvider"/>
</extensions>
<project-components>
<component>
<implementation-class>com.jetbrains.python.actions.PySciProjectComponent</implementation-class>
</component>
</project-components>
<project-components>
<component>
<implementation-class>com.jetbrains.python.plots.PyPlotToolWindow</implementation-class>
</component>
</project-components>
<application-components>
<component>
<implementation-class>com.jetbrains.python.testing.VFSTestFrameworkListener</implementation-class>
@@ -1,235 +0,0 @@
/*
* 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.actions;
import com.intellij.codeInsight.documentation.DocumentationManager;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.AbstractProjectComponent;
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiManager;
import com.intellij.ui.content.Content;
import com.intellij.util.ui.UIUtil;
import com.jetbrains.python.plots.PyPlotToolWindow;
import org.jetbrains.annotations.Nullable;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import static com.intellij.codeInsight.documentation.DocumentationComponent.COLOR_KEY;
import static com.jetbrains.python.actions.PySciViewAction.hideDataViewer;
import static com.jetbrains.python.actions.PySciViewAction.showDataViewAsToolwindow;
import static com.jetbrains.python.debugger.containerview.PyDataView.DATA_VIEWER_ID;
@State(name = "PySciProjectComponent", storages = @Storage("other.xml"))
public class PySciProjectComponent extends AbstractProjectComponent implements PersistentStateComponent<PySciProjectComponent.State> {
private State myState = new State();
private ServerSocket myServerSocket;
private Thread myPlotsThread;
private volatile boolean myShouldAccept = true;
private static final Logger LOG = Logger.getInstance(PySciProjectComponent.class);
protected PySciProjectComponent(Project project) {
super(project);
}
public static PySciProjectComponent getInstance(Project project) {
return project.getComponent(PySciProjectComponent.class);
}
public void useSciView(boolean useSciView) {
myState.PY_SCI_VIEW = useSciView;
}
public void sciViewSuggested(boolean suggested) {
myState.PY_SCI_VIEW_SUGGESTED = suggested;
}
public boolean sciViewSuggested() {
return myState.PY_SCI_VIEW_SUGGESTED;
}
public boolean useSciView() {
return myState.PY_SCI_VIEW;
}
public void matplotlibInToolwindow(boolean inToolwindow) {
myState.PY_MATPLOTLIB_IN_TOOLWINDOW = inToolwindow;
if (inToolwindow) {
if (myServerSocket == null) {
initializeServerSocket();
}
if (!useSciView()) {
showDataViewAsToolwindow(myProject);
}
}
else if (!useSciView()) {
hideDataViewer(myProject);
}
}
public boolean matplotlibInToolwindow() {
return myState.PY_MATPLOTLIB_IN_TOOLWINDOW;
}
@Override
public void projectOpened() {
final VirtualFile baseDir = myProject.getBaseDir();
if (baseDir == null) return;
if (ApplicationManager.getApplication().isUnitTestMode()) return;
if (myState.PY_SCI_VIEW) {
StartupManager.getInstance(myProject).runWhenProjectIsInitialized(() -> {
EditorColorsScheme scheme = EditorColorsManager.getInstance().getGlobalScheme();
scheme.setColor(COLOR_KEY, UIUtil.getEditorPaneBackground());
final PsiDirectory directory = PsiManager.getInstance(myProject).findDirectory(baseDir);
if (directory != null) {
DocumentationManager.getInstance(myProject).showJavaDocInfo(directory, directory);
}
});
}
if (matplotlibInToolwindow()) {
initializeServerSocket();
if (!useSciView()) {
StartupManager.getInstance(myProject).runWhenProjectIsInitialized(() -> showDataViewAsToolwindow(myProject));
}
}
}
private void initializeServerSocket() {
try {
myServerSocket = new ServerSocket(0);
}
catch (IOException e) {
LOG.error("Failed to initialize server socket for python plots " + e.getMessage());
return;
}
myPlotsThread = new Thread(()->{
while (myShouldAccept) {
processConnection();
}
}, "Python plots client");
myPlotsThread.setDaemon(true);
myPlotsThread.start();
}
private void processConnection() {
try {
final Socket socket = myServerSocket.accept();
try {
final InputStream stream = socket.getInputStream();
final DataInputStream inputStream = new DataInputStream(stream);
try {
final int width = inputStream.readInt();
final int count = inputStream.readInt();
final byte[] raw = new byte[count];
inputStream.readFully(raw);
PyPlotToolWindow.getInstance(myProject).onMessage(width, raw);
ToolWindow window = ToolWindowManager.getInstance(myProject).getToolWindow(DATA_VIEWER_ID);
if (window == null) {
return;
}
ApplicationManager.getApplication().invokeLater(() -> {
window.show(null);
final Content plotsTab = window.getContentManager().getContent(1);
if (plotsTab != null) {
window.getContentManager().setSelectedContent(plotsTab);
}
});
}
catch (IOException e) {
LOG.error(e.getMessage());
}
finally {
inputStream.close();
}
}
finally {
if (!socket.isClosed()) {
socket.close();
}
}
}
catch (IOException e) {
if (myServerSocket == null) {
myShouldAccept = false;
}
}
}
public void stopMatplotlibCommunication() {
if (myServerSocket != null && !myServerSocket.isClosed()) {
try {
myServerSocket.close();
} catch (IOException ignore) {
}
}
myShouldAccept = false;
myServerSocket = null;
try {
if (myPlotsThread != null) {
myPlotsThread.join();
}
}
catch (InterruptedException ignored) {
}
}
public int getPort() {
return myServerSocket != null ? myServerSocket.getLocalPort() : -1;
}
@Override
public void projectClosed() {
stopMatplotlibCommunication();
}
@Nullable
@Override
public PySciProjectComponent.State getState() {
return myState;
}
@Override
public void loadState(PySciProjectComponent.State state) {
myState.PY_SCI_VIEW = state.PY_SCI_VIEW;
myState.PY_SCI_VIEW_SUGGESTED = state.PY_SCI_VIEW_SUGGESTED;
myState.PY_MATPLOTLIB_IN_TOOLWINDOW = state.PY_MATPLOTLIB_IN_TOOLWINDOW;
}
public static class State {
public boolean PY_SCI_VIEW = false;
public boolean PY_SCI_VIEW_SUGGESTED = false;
public boolean PY_MATPLOTLIB_IN_TOOLWINDOW = true;
}
}
@@ -1,214 +0,0 @@
/*
* 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.actions;
import com.intellij.codeInsight.documentation.DocumentationManager;
import com.intellij.execution.RunManager;
import com.intellij.execution.RunnerAndConfigurationSettings;
import com.intellij.execution.configurations.RunConfiguration;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.actionSystem.ToggleAction;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.options.FontSize;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowId;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.openapi.wm.ToolWindowType;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiManager;
import com.intellij.util.ui.UIUtil;
import com.jetbrains.python.console.PythonConsoleToolWindow;
import com.jetbrains.python.documentation.PyDocumentationSettings;
import com.jetbrains.python.run.PythonConfigurationType;
import com.jetbrains.python.run.PythonRunConfiguration;
import org.jetbrains.annotations.NotNull;
import java.awt.*;
import static com.intellij.codeInsight.documentation.DocumentationComponent.COLOR_KEY;
import static com.intellij.codeInsight.documentation.DocumentationComponent.QUICK_DOC_FONT_SIZE_PROPERTY;
import static com.jetbrains.python.debugger.containerview.PyDataView.DATA_VIEWER_ID;
public class PySciViewAction extends ToggleAction implements DumbAware {
private static final String TEXT_SCI_VIEW = "Scientific Mode";
private boolean wasConsoleVisible = false;
public static final String ACTION_ID = "PySciView";
private Color myDocumentationBackgroundColor = EditorColorsManager.getInstance().getGlobalScheme().getColor(COLOR_KEY);
public PySciViewAction() {
super(TEXT_SCI_VIEW);
}
@Override
public boolean isSelected(AnActionEvent e) {
return e.getProject() != null && PySciProjectComponent.getInstance(e.getProject()).useSciView();
}
@Override
public void setSelected(AnActionEvent e, boolean state) {
final Project project = e.getProject();
if (project == null) return;
PySciProjectComponent.getInstance(project).useSciView(state);
final PsiElement element = getPsiElement(e, project);
if (state) {
showConsoleToolwindow(project);
showDocumentationToolwindow(project, element);
showDataViewAsToolwindow(project);
showCommandLineInRunConfiguration(project, true);
renderExternalDocumentation(element, true);
}
else {
hideConsoleToolwindow(project);
restoreDocumentationPopup(project);
hideDataViewer(project);
showCommandLineInRunConfiguration(project, false);
renderExternalDocumentation(element, false);
}
}
private static void renderExternalDocumentation(PsiElement element, boolean render) {
final Module module = ModuleUtilCore.findModuleForPsiElement(element);
if (module != null) {
PyDocumentationSettings.getInstance(module).setRenderExternalDocumentation(render);
}
}
private static void showCommandLineInRunConfiguration(Project project, boolean show) {
final RunnerAndConfigurationSettings template =
RunManager.getInstance(project).getConfigurationTemplate(PythonConfigurationType.getInstance().getFactory());
final RunConfiguration configuration = template.getConfiguration();
if (configuration instanceof PythonRunConfiguration) {
((PythonRunConfiguration)configuration).setShowCommandLineAfterwards(show);
}
}
private void showConsoleToolwindow(@NotNull final Project project) {
final PythonConsoleToolWindow pythonConsoleToolWindow = PythonConsoleToolWindow.getInstance(project);
if (pythonConsoleToolWindow == null) return;
final ToolWindow consoleToolWindow = pythonConsoleToolWindow.getToolWindow();
if (consoleToolWindow == null) return;
wasConsoleVisible = consoleToolWindow.isVisible();
consoleToolWindow.show(null);
}
private void hideConsoleToolwindow(@NotNull final Project project) {
if (!wasConsoleVisible) {
final PythonConsoleToolWindow pythonConsoleToolWindow = PythonConsoleToolWindow.getInstance(project);
if (pythonConsoleToolWindow != null) {
final ToolWindow consoleToolWindow = pythonConsoleToolWindow.getToolWindow();
if (consoleToolWindow != null) {
consoleToolWindow.hide(null);
}
}
}
}
private void showDocumentationToolwindow(Project project, PsiElement element) {
final String showInToolWindowProperty = DocumentationManager.getInstance(project).getShowInToolWindowProperty();
EditorColorsScheme scheme = EditorColorsManager.getInstance().getGlobalScheme();
myDocumentationBackgroundColor = scheme.getColor(COLOR_KEY);
scheme.setColor(COLOR_KEY, UIUtil.getEditorPaneBackground());
PropertiesComponent.getInstance().setValue(showInToolWindowProperty, true);
PropertiesComponent.getInstance().setValue(DocumentationManager.getInstance(project).getAutoUpdateEnabledProperty(), true);
if (element != null) {
DocumentationManager.getInstance(project).showJavaDocInfo(element, element);
}
setDocFontSize();
}
private static void setDocFontSize() {
EditorColorsScheme scheme = EditorColorsManager.getInstance().getGlobalScheme();
final int editorFontSize = scheme.getEditorFontSize();
final FontSize[] values = FontSize.values();
FontSize fontSize = FontSize.MEDIUM;
for (FontSize value : values) {
if (value.getSize() > editorFontSize) {
break;
}
fontSize = value;
}
PropertiesComponent.getInstance().setValue(QUICK_DOC_FONT_SIZE_PROPERTY, String.valueOf(fontSize.toString()));
}
private void restoreDocumentationPopup(Project project) {
PropertiesComponent.getInstance().setValue(DocumentationManager.getInstance(project).getAutoUpdateEnabledProperty(), false);
EditorColorsScheme scheme = EditorColorsManager.getInstance().getGlobalScheme();
scheme.setColor(COLOR_KEY, myDocumentationBackgroundColor);
final ToolWindow window = ToolWindowManager.getInstance(project).getToolWindow(ToolWindowId.DOCUMENTATION);
if (window != null) {
DocumentationManager.getInstance(project).restorePopupBehavior();
final JBPopup hint = DocumentationManager.getInstance(project).getDocInfoHint();
if (hint != null) {
hint.cancel();
}
}
}
public static void showDataViewAsToolwindow(@NotNull final Project project) {
ToolWindow dataViewToolWindow = ToolWindowManager.getInstance(project).getToolWindow(DATA_VIEWER_ID);
if (dataViewToolWindow != null) {
dataViewToolWindow.setType(ToolWindowType.DOCKED, null);
dataViewToolWindow.setAutoHide(false);
dataViewToolWindow.setShowStripeButton(true);
}
}
public static void hideDataViewer(Project project) {
final ToolWindow dataViewer = ToolWindowManager.getInstance(project).getToolWindow(DATA_VIEWER_ID);
if (dataViewer != null) {
dataViewer.setType(ToolWindowType.FLOATING, null);
dataViewer.setAutoHide(true);
dataViewer.setShowStripeButton(false);
}
}
private static PsiElement getPsiElement(AnActionEvent e, Project project) {
PsiElement element = CommonDataKeys.PSI_ELEMENT.getData(e.getDataContext());
if (element == null) {
element = CommonDataKeys.PSI_FILE.getData(e.getDataContext());
}
if (element == null) {
element = PsiManager.getInstance(project).findDirectory(project.getBaseDir());
}
return element;
}
@Override
public void update(@NotNull AnActionEvent e) {
super.update(e);
final Project project = e.getProject();
final Presentation presentation = e.getPresentation();
presentation.setEnabledAndVisible(project != null);
}
}
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.jetbrains.python.configuration.PyIntegratedToolsConfigurable">
<grid id="27dc6" binding="myMainPanel" layout-manager="GridLayoutManager" row-count="9" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<grid id="27dc6" binding="myMainPanel" layout-manager="GridLayoutManager" row-count="8" 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="20" y="20" width="657" height="304"/>
<xy x="20" y="20" width="657" height="275"/>
</constraints>
<properties/>
<border type="none"/>
@@ -24,12 +24,12 @@
</component>
<vspacer id="fc19e">
<constraints>
<grid row="8" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
<grid row="7" 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>
<grid id="728f8" binding="myErrorPanel" layout-manager="BorderLayout" hgap="0" vgap="0">
<constraints>
<grid row="7" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
<grid row="6" 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"/>
@@ -52,7 +52,7 @@
<grid id="e7a5f" binding="myDocStringsPanel" 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>
<grid row="3" column="0" row-span="2" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
<grid row="2" column="0" row-span="2" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
@@ -95,7 +95,7 @@
<grid id="9f040" binding="myRestPanel" layout-manager="GridLayoutManager" row-count="2" 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="5" column="0" row-span="2" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
<grid row="4" column="0" row-span="2" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
@@ -125,14 +125,6 @@
</component>
</children>
</grid>
<component id="5432b" class="javax.swing.JCheckBox" binding="myShowPlots">
<constraints>
<grid row="2" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Show plots in toolwindow"/>
</properties>
</component>
</children>
</grid>
</form>
@@ -41,7 +41,6 @@ import com.intellij.util.FileContentUtilCore;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.PythonFileType;
import com.jetbrains.python.ReSTService;
import com.jetbrains.python.actions.PySciProjectComponent;
import com.jetbrains.python.documentation.PyDocumentationSettings;
import com.jetbrains.python.documentation.docstrings.DocStringFormat;
import com.jetbrains.python.packaging.PyPackageManagerUI;
@@ -79,7 +78,6 @@ public class PyIntegratedToolsConfigurable implements SearchableConfigurable {
private JPanel myDocStringsPanel;
private JPanel myRestPanel;
private JCheckBox renderExternal;
private JCheckBox myShowPlots;
public PyIntegratedToolsConfigurable(@NotNull Module module) {
myModule = module;
@@ -102,7 +100,6 @@ public class PyIntegratedToolsConfigurable implements SearchableConfigurable {
txtIsRst.setSelected(service.txtIsRst());
analyzeDoctest.setSelected(myDocumentationSettings.isAnalyzeDoctest());
renderExternal.setSelected(myDocumentationSettings.isRenderExternalDocumentation());
myShowPlots.setSelected(PySciProjectComponent.getInstance(myProject).matplotlibInToolwindow());
myRequirementsPathField.addBrowseFolderListener("Choose path to the package requirements file:", null, myProject,
FileChooserDescriptorFactory.createSingleLocalFileDescriptor());
myRequirementsPathField.setText(getRequirementsPath());
@@ -214,9 +211,6 @@ public class PyIntegratedToolsConfigurable implements SearchableConfigurable {
if (renderExternal.isSelected() != myDocumentationSettings.isRenderExternalDocumentation()) {
return true;
}
if (myShowPlots.isSelected() != PySciProjectComponent.getInstance(myProject).matplotlibInToolwindow()) {
return true;
}
if (!ReSTService.getInstance(myModule).getWorkdir().equals(myWorkDir.getText())) {
return true;
}
@@ -246,7 +240,6 @@ public class PyIntegratedToolsConfigurable implements SearchableConfigurable {
}
myModel.apply();
myDocumentationSettings.setRenderExternalDocumentation(renderExternal.isSelected());
PySciProjectComponent.getInstance(myProject).matplotlibInToolwindow(myShowPlots.isSelected());
myDocumentationSettings.setFormat((DocStringFormat)myDocstringFormatComboBox.getSelectedItem());
final ReSTService reSTService = ReSTService.getInstance(myModule);
reSTService.setWorkdir(myWorkDir.getText());
@@ -284,7 +277,6 @@ public class PyIntegratedToolsConfigurable implements SearchableConfigurable {
txtIsRst.setSelected(ReSTService.getInstance(myModule).txtIsRst());
analyzeDoctest.setSelected(myDocumentationSettings.isAnalyzeDoctest());
renderExternal.setSelected(myDocumentationSettings.isRenderExternalDocumentation());
myShowPlots.setSelected(PySciProjectComponent.getInstance(myProject).matplotlibInToolwindow());
myRequirementsPathField.setText(getRequirementsPath());
}
@@ -65,7 +65,19 @@ public class PyDataView implements DumbAware {
myProject = project;
}
public void show(@NotNull PyDebugValue value) {
public void show(@NotNull PyDebugValue value, boolean inToolwindow) {
if (inToolwindow) {
showInToolwindow(value);
}
else {
ApplicationManager.getApplication().invokeLater(() -> {
final PyDataViewDialog dialog = new PyDataViewDialog(myProject, value);
dialog.show();
});
}
}
private void showInToolwindow(@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");
@@ -0,0 +1,78 @@
/*
* 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.ide.util.PropertiesComponent;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.VerticalFlowLayout;
import com.intellij.ui.JBColor;
import com.intellij.ui.components.JBCheckBox;
import com.jetbrains.python.debugger.PyDebugValue;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class PyDataViewDialog extends DialogWrapper {
private final JPanel myMainPanel;
PyDataViewDialog(@NotNull Project project, @NotNull final PyDebugValue value) {
super(project, false);
setModal(false);
setCancelButtonText("Close");
setCrossClosesWindow(true);
myMainPanel = new JPanel(new VerticalFlowLayout());
final PyDataViewerPanel panel = new PyDataViewerPanel(project, value.getFrameAccessor());
panel.apply(value);
myMainPanel.add(panel);
panel.setBorder(BorderFactory.createLineBorder(JBColor.GRAY));
final JBCheckBox colored = new JBCheckBox("Colored cells");
final JBCheckBox resize = new JBCheckBox("Resize Automatically");
resize.setSelected(PropertiesComponent.getInstance(project).getBoolean(PyDataView.AUTO_RESIZE, true));
colored.setSelected(PropertiesComponent.getInstance(project).getBoolean(PyDataView.COLORED_BY_DEFAULT, true));
colored.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
panel.setColored(colored.isSelected());
panel.updateUI();
}
});
resize.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
panel.resize(resize.isSelected());
panel.updateUI();
}
});
myMainPanel.add(colored);
myMainPanel.add(resize);
setTitle(value.getFullName());
init();
}
@Override
@NotNull
protected Action[] createActions() {
return new Action[]{getCancelAction()};
}
@Override
protected JComponent createCenterPanel() {
return myMainPanel;
}
}
@@ -28,7 +28,7 @@ import org.jetbrains.annotations.Nullable;
import java.awt.*;
class PyDataViewTabs extends JBRunnerTabs {
public static final String EMPTY_TEXT = "Run debugger to view available data ";
private static final String HELP_ID = "reference.toolWindows.PyDataView";
public PyDataViewTabs(@NotNull Project project) {
@@ -40,7 +40,7 @@ class PyDataViewTabs extends JBRunnerTabs {
super.paintComponent(g);
if (isEmptyVisible()) {
UISettings.setupAntialiasing(g);
UIUtil.drawCenteredString((Graphics2D)g, g.getClipBounds(), PyDataViewToolWindowFactory.EMPTY_TEXT);
UIUtil.drawCenteredString((Graphics2D)g, g.getClipBounds(), EMPTY_TEXT);
}
}
@@ -1,147 +0,0 @@
/*
* 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.Executor;
import com.intellij.execution.executors.DefaultDebugExecutor;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.ui.RunContentDescriptor;
import com.intellij.execution.ui.RunContentManager;
import com.intellij.execution.ui.RunContentWithExecutorListener;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.actionSystem.ToggleAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowFactory;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.openapi.wm.ex.ToolWindowEx;
import com.intellij.ui.content.ContentManagerAdapter;
import com.intellij.ui.content.ContentManagerEvent;
import com.intellij.util.messages.MessageBusConnection;
import com.intellij.xdebugger.XDebugProcess;
import com.intellij.xdebugger.XDebuggerManager;
import com.intellij.xdebugger.XDebuggerManagerListener;
import com.jetbrains.python.console.PythonConsoleToolWindowFactory;
import com.jetbrains.python.debugger.PyDebugProcess;
import com.jetbrains.python.plots.PyPlotToolWindow;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class PyDataViewToolWindowFactory implements ToolWindowFactory {
public static final String EMPTY_TEXT = "Run debugger to view available data ";
private static final Logger LOG = Logger.getInstance(PyDataViewToolWindowFactory.class);
@Override
public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) {
initializeDataTab(project, toolWindow);
PyPlotToolWindow.getInstance(project).init(toolWindow);
}
private static void initializeDataTab(@NotNull Project project, @NotNull ToolWindow toolWindow) {
PyDataView.getInstance(project).init(toolWindow);
final MessageBusConnection connection = project.getMessageBus().connect(project);
connection.subscribe(XDebuggerManager.TOPIC, new ChangeContentXDebuggerManagerListener(project));
connection.subscribe(RunContentManager.TOPIC, new RunContentWithExecutorListener() {
@Override
public void contentSelected(@Nullable RunContentDescriptor descriptor, @NotNull Executor executor) {
if (!(executor instanceof DefaultDebugExecutor)) {
return;
}
if (descriptor == null) {
return;
}
ProcessHandler handler = descriptor.getProcessHandler();
if (handler == null) {
return;
}
PyDataView.getInstance(project).updateTabs(handler);
}
@Override
public void contentRemoved(@Nullable RunContentDescriptor descriptor, @NotNull Executor executor) {
}
});
addPythonConsoleListener(project);
PyDataViewToggleAction autoResizeAction = new PyDataViewToggleAction("Resize Automatically", PyDataView.AUTO_RESIZE) {
@Override
public void setSelected(AnActionEvent e, boolean state) {
super.setSelected(e, state);
PyDataView.getInstance(project).changeAutoResize(state);
}
};
DefaultActionGroup group = new DefaultActionGroup(new PyDataViewToggleAction("Colored by Default", PyDataView.COLORED_BY_DEFAULT),
autoResizeAction);
((ToolWindowEx)toolWindow).setAdditionalGearActions(group);
}
private static void addPythonConsoleListener(@NotNull Project project) {
final ToolWindow pythonConsole = ToolWindowManager.getInstance(project).getToolWindow(PythonConsoleToolWindowFactory.Companion.getID());
if (pythonConsole == null) {
return;
}
pythonConsole.getContentManager().addContentManagerListener(new ContentManagerAdapter() {
@Override
public void contentRemoved(ContentManagerEvent event) {
PyDataView.getInstance(project).closeDisconnectedFromConsoleTabs();
}
});
}
private static class PyDataViewToggleAction extends ToggleAction {
private final String myPropertyKey;
public PyDataViewToggleAction(String text, String propertyKey) {
super(text);
myPropertyKey = propertyKey;
}
@Override
public boolean isSelected(AnActionEvent e) {
return PropertiesComponent.getInstance(e.getProject()).getBoolean(myPropertyKey, true);
}
@Override
public void setSelected(AnActionEvent e, boolean state) {
PropertiesComponent.getInstance(e.getProject()).setValue(myPropertyKey, state, true);
}
}
private static class ChangeContentXDebuggerManagerListener implements XDebuggerManagerListener {
private final Project myProject;
public ChangeContentXDebuggerManagerListener(Project project) {
myProject = project;
}
@Override
public void processStarted(@NotNull XDebugProcess debugProcess) {
}
@Override
public void processStopped(@NotNull XDebugProcess debugProcess) {
if (debugProcess instanceof PyDebugProcess) {
PyDataView.getInstance(myProject).closeTabs(frameAccessor -> frameAccessor instanceof PyDebugProcess && frameAccessor == debugProcess);
}
}
}
}
@@ -18,6 +18,7 @@ package com.jetbrains.python.debugger.containerview;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.project.Project;
import com.intellij.util.PlatformUtils;
import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree;
import com.intellij.xdebugger.impl.ui.tree.actions.XDebuggerTreeActionBase;
import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
@@ -43,7 +44,7 @@ public class PyViewNumericContainerAction extends XDebuggerTreeActionBase {
}
public static void showNumericViewer(Project project, PyDebugValue debugValue) {
PyDataView.getInstance(project).show(debugValue);
PyDataView.getInstance(project).show(debugValue, PlatformUtils.isPyCharmPro());
}
@Nullable
@@ -1,118 +0,0 @@
/*
* 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.inspections;
import com.intellij.ide.DataManager;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.lang.annotation.Annotator;
import com.intellij.notification.NotificationDisplayType;
import com.intellij.notification.NotificationGroup;
import com.intellij.notification.NotificationListener;
import com.intellij.notification.NotificationType;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.ActionPlaces;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.FileIndexFacade;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.QualifiedName;
import com.jetbrains.python.actions.PySciProjectComponent;
import com.jetbrains.python.actions.PySciViewAction;
import com.jetbrains.python.psi.PyFile;
import com.jetbrains.python.psi.PyImportElement;
import org.jetbrains.annotations.NotNull;
import static com.jetbrains.python.actions.PySciViewAction.ACTION_ID;
public class PySciViewAdvertiser implements Annotator {
private static final NotificationGroup BALLOON_NOTIFICATIONS = new NotificationGroup("Python Scientific View Advertiser",
NotificationDisplayType.STICKY_BALLOON, false);
private static final Key<Boolean> BALLOON_SHOWING = Key.create("showingSciViewAdvertiserBalloon");
@Override
public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) {
if (element instanceof PyFile) {
final PyFile pyFile = (PyFile)element;
final Project project = element.getProject();
if (PySciProjectComponent.getInstance(project).sciViewSuggested()) {
return;
}
final VirtualFile vFile = pyFile.getVirtualFile();
if (vFile != null && FileIndexFacade.getInstance(project).isInLibraryClasses(vFile)) {
return;
}
final Boolean showingFlag = project.getUserData(BALLOON_SHOWING);
if (showingFlag != null && showingFlag.booleanValue()) {
return;
}
if (containsNumpyImports(pyFile)) {
showInspectionAdvertisement(project);
}
}
}
private static void showInspectionAdvertisement(@NotNull Project project) {
final String msg = "Your source code imports the 'numpy' package." +
"<br/>Would you like to enable Scientific View?<br/>" +
"<a href=\"#yes\">Yes</a>&nbsp;&nbsp;<a href=\"#no\">No</a>";
showSingletonNotification(project, msg, NotificationType.INFORMATION, (notification, event) -> {
final boolean enabled = "#yes".equals(event.getDescription());
PySciProjectComponent.getInstance(project).sciViewSuggested(true);
if (enabled) {
final AnAction action = ActionManager.getInstance().getAction(ACTION_ID);
if (action instanceof PySciViewAction) {
PySciProjectComponent.getInstance(project).sciViewSuggested();
final AnActionEvent anActionEvent = AnActionEvent.createFromDataContext(
ActionPlaces.UNKNOWN, null, DataManager.getInstance().getDataContextFromFocus().getResult());
((PySciViewAction)action).setSelected(anActionEvent, true);
}
}
});
}
private static void showSingletonNotification(@NotNull Project project,
@NotNull String htmlContent,
@NotNull NotificationType type,
@NotNull NotificationListener listener) {
project.putUserData(BALLOON_SHOWING, true);
BALLOON_NOTIFICATIONS.createNotification("Scientific View", htmlContent, type, (notification, event) -> {
try {
listener.hyperlinkUpdate(notification, event);
}
finally {
notification.expire();
}
}).notify(project);
}
private static boolean containsNumpyImports(@NotNull PyFile file) {
for (PyImportElement importTarget : file.getImportTargets()) {
final QualifiedName qName = importTarget.getImportedQName();
if (qName != null && qName.matches("numpy")) {
return true;
}
}
return false;
}
}
@@ -1,355 +0,0 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR 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.plots;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.Disposable;
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.fileChooser.FileChooserFactory;
import com.intellij.openapi.fileChooser.FileSaverDescriptor;
import com.intellij.openapi.fileChooser.FileSaverDialog;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.fileEditor.FileEditorProvider;
import com.intellij.openapi.fileEditor.ex.FileEditorProviderManager;
import com.intellij.openapi.fileEditor.impl.EditorTabbedContainer;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.VirtualFileWrapper;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.testFramework.BinaryLightVirtualFile;
import com.intellij.ui.JBColor;
import com.intellij.ui.SimpleColoredComponent;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.awt.RelativeRectangle;
import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentFactory;
import com.intellij.ui.docking.DockContainer;
import com.intellij.ui.docking.DockManager;
import com.intellij.ui.docking.DockableContent;
import com.intellij.ui.docking.DragSession;
import com.intellij.ui.tabs.JBTabsPosition;
import com.intellij.ui.tabs.TabInfo;
import com.intellij.ui.tabs.impl.DefaultEditorTabsPainter;
import com.intellij.ui.tabs.impl.JBEditorTabs;
import com.intellij.ui.tabs.impl.JBTabsImpl;
import com.intellij.ui.tabs.impl.TabLabel;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
public class PyPlotToolWindow extends JPanel implements DumbAware {
public static final String PLOT_DEFAULT_NAME = "myplot";
public static final String PLOT_FORMAT = "png";
private final static int ourPreviewSize = 80;
private final JBEditorTabs myTabs;
private final Project myProject;
private static final Logger LOG = Logger.getInstance(PyPlotToolWindow.class);
private MyDockContainer myDockContainer;
public PyPlotToolWindow(final Project project) {
super(new BorderLayout());
myProject = project;
myTabs = new MyTabs(myProject);
myTabs.setTabsPosition(JBTabsPosition.right);
myTabs.setPopupGroup(new DefaultActionGroup(new SaveAsFileAction()), ActionPlaces.UNKNOWN, true);
myTabs.setTabDraggingEnabled(true);
add(myTabs);
}
public void onMessage(int width, byte[] raw) {
final PyPlotVirtualFile plotVirtualFile = new PyPlotVirtualFile(width, raw);
final TabInfo info = createTabInfo(plotVirtualFile);
ApplicationManager.getApplication().invokeLater(() -> {
myTabs.addTab(info);
myTabs.select(info, true);
});
}
@NotNull
private TabInfo createTabInfo(@NotNull final PyPlotVirtualFile plotVirtualFile) {
final JPanel panel = new MyPlotPanel(plotVirtualFile);
final TabInfo info = new TabInfo(panel);
info.setTabColor(UIUtil.getPanelBackground());
final BufferedImage image = plotVirtualFile.getImage();
final Image after = image.getScaledInstance(JBUI.scale(64), JBUI.scale(48), Image.SCALE_SMOOTH);
info.setIcon(new ImageIcon(after));
info.setText(" ");
info.setTabLabelActions(new DefaultActionGroup(new ClosePlotAction(info)), ActionPlaces.UNKNOWN);
info.setDragOutDelegate(new MyDragOutDelegate());
return info;
}
public void init(ToolWindow toolWindow) {
final ContentFactory contentFactory = ContentFactory.SERVICE.getInstance();
Content content = contentFactory.createContent(this, "Plots", false);
content.setCloseable(false);
toolWindow.getContentManager().addContent(content);
if (myDockContainer == null) {
myDockContainer = new MyDockContainer(toolWindow);
Disposer.register(myProject, myDockContainer);
DockManager.getInstance(myProject).register(myDockContainer);
}
}
public static PyPlotToolWindow getInstance(@NotNull final Project project) {
return ServiceManager.getService(project, PyPlotToolWindow.class);
}
private static class MyTabs extends JBEditorTabs {
public MyTabs(Project project) {
super(project, ActionManager.getInstance(), IdeFocusManager.findInstance(), project);
myDefaultPainter = new DefaultEditorTabsPainter(this) {
@Override
public Color getBackgroundColor() {
return JBColor.LIGHT_GRAY;
}
};
}
@Override
protected TabLabel createTabLabel(TabInfo info) {
return new MyTabLabel(this, info);
}
}
private static class MyTabLabel extends TabLabel {
public MyTabLabel(JBTabsImpl tabs, TabInfo info) {
super(tabs, info);
final JComponent label = getLabelComponent();
if (label instanceof SimpleColoredComponent) {
((SimpleColoredComponent)label).setIconOnTheRight(true);
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(JBUI.scale(ourPreviewSize + 20), JBUI.scale(ourPreviewSize));
}
}
private class ClosePlotAction extends AnAction {
private final TabInfo myInfo;
public ClosePlotAction(TabInfo info) {
super("Close Plot", "Close selected plot", AllIcons.Actions.Close);
myInfo = info;
}
@Override
public void actionPerformed(AnActionEvent e) {
myTabs.removeTab(myInfo);
}
}
private class SaveAsFileAction extends AnAction {
public SaveAsFileAction() {
super("Save as File");
}
@Override
public void actionPerformed(AnActionEvent e) {
TabInfo info = myTabs.getSelectedInfo();
final Project project = e.getProject();
if (info != null && project != null) {
final MyPlotPanel component = (MyPlotPanel)info.getComponent();
final BinaryLightVirtualFile virtualFile = component.getVirtualFile();
FileSaverDescriptor descriptor = new FileSaverDescriptor("Select File to Save Plot", "", PLOT_FORMAT);
final FileSaverDialog chooser = FileChooserFactory.getInstance().createSaveFileDialog(descriptor, project);
final VirtualFileWrapper fileWrapper = chooser.save(project.getBaseDir(), PLOT_DEFAULT_NAME);
try {
if (fileWrapper != null) {
final File ioFile = fileWrapper.getFile();
Files.write(Paths.get(ioFile.getPath()), virtualFile.getContent());
}
}
catch (IOException e1) {
LOG.warn("Failed to save image " + e1.getMessage());
}
}
}
}
private class MyPlotPanel extends JPanel {
private final PyPlotVirtualFile myVirtualFile;
public MyPlotPanel(PyPlotVirtualFile virtualFile) {
super(new BorderLayout());
myVirtualFile = virtualFile;
ApplicationManager.getApplication().invokeLater(() -> {
//ImageFileEditorProvider#EDITOR_TYPE_ID
final FileEditorProvider provider = FileEditorProviderManager.getInstance().getProvider("images");
if (provider != null) {
final FileEditor editor = provider.createEditor(myProject, myVirtualFile);
Disposer.register(myProject, editor);
add(editor.getComponent());
}
});
setBackground(UIUtil.getEditorPaneBackground());
}
public BinaryLightVirtualFile getVirtualFile() {
return myVirtualFile;
}
}
class MyDragOutDelegate implements TabInfo.DragOutDelegate {
private DragSession mySession;
@Override
public void dragOutStarted(MouseEvent mouseEvent, TabInfo info) {
final TabInfo previousSelection = info.getPreviousSelection();
final Image img = JBTabsImpl.getComponentImage(info);
info.setHidden(true);
if (previousSelection != null) {
myTabs.select(previousSelection, true);
}
Presentation presentation = new Presentation(info.getText());
presentation.setIcon(info.getIcon());
final MyPlotPanel component = (MyPlotPanel)info.getComponent();
final BinaryLightVirtualFile file = component.getVirtualFile();
mySession = getDockManager().createDragSession(mouseEvent, new EditorTabbedContainer.DockableEditor(myProject, img, file, presentation,
info.getComponent().getPreferredSize(), false));
}
private DockManager getDockManager() {
return DockManager.getInstance(myProject);
}
@Override
public void processDragOut(MouseEvent event, TabInfo source) {
mySession.process(event);
}
@Override
public void dragOutFinished(MouseEvent event, TabInfo source) {
myTabs.removeTab(source);
mySession.process(event);
mySession = null;
}
@Override
public void dragOutCancelled(TabInfo source) {
source.setHidden(false);
if (mySession != null) {
mySession.cancel();
}
mySession = null;
}
}
public class MyDockContainer implements DockContainer {
private final ToolWindow myToolWindow;
public MyDockContainer(ToolWindow toolWindow) {
myToolWindow = toolWindow;
}
@Override
public RelativeRectangle getAcceptArea() {
return new RelativeRectangle(myToolWindow.getComponent());
}
@Override
public RelativeRectangle getAcceptAreaFallback() {
return getAcceptArea();
}
@NotNull
@Override
public ContentResponse getContentResponse(@NotNull DockableContent content, RelativePoint point) {
return content.getKey() instanceof PyPlotVirtualFile ? ContentResponse.ACCEPT_MOVE : ContentResponse.DENY;
}
@Override
public JComponent getContainerComponent() {
return myToolWindow.getComponent();
}
@Override
public void add(@NotNull DockableContent content, RelativePoint dropTarget) {
final Object key = content.getKey();
if (key instanceof PyPlotVirtualFile) {
final TabInfo info = createTabInfo((PyPlotVirtualFile)key);
myTabs.addTab(info);
}
}
@Override
public void closeAll() {}
@Override
public void addListener(Listener listener, Disposable parent) {}
@Override
public boolean isEmpty() {
return false;
}
@Nullable
@Override
public Image startDropOver(@NotNull DockableContent content, RelativePoint point) {
return null;
}
@Nullable
@Override
public Image processDropOver(@NotNull DockableContent content, RelativePoint point) {
return null;
}
@Override
public void resetDropOver(@NotNull DockableContent content) {}
@Override
public boolean isDisposeWhenEmpty() {
return false;
}
@Override
public void dispose() {}
@Override
public void showNotify() {}
@Override
public void hideNotify() {}
}
}
@@ -1,78 +0,0 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR 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.plots;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.testFramework.BinaryLightVirtualFile;
import com.intellij.util.ui.UIUtil;
import javax.imageio.ImageIO;
import java.awt.image.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
public class PyPlotVirtualFile extends BinaryLightVirtualFile {
private static final Logger LOG = Logger.getInstance(PyPlotToolWindow.class);
private BufferedImage myImage;
public PyPlotVirtualFile(int width, byte[] raw) {
super(PyPlotToolWindow.PLOT_DEFAULT_NAME + "." + PyPlotToolWindow.PLOT_FORMAT);
int height = raw.length / 3 / width;
final DataBuffer buffer = new DataBufferByte(raw, raw.length);
final SampleModel sampleModel = new ComponentSampleModel(DataBuffer.TYPE_BYTE, width, height, 3, width * 3,
new int[]{0, 1, 2});
final Raster raster = Raster.createRaster(sampleModel, buffer, null);
myImage = UIUtil.createImage(width, height, BufferedImage.TYPE_INT_RGB);
if (SystemInfo.isMac && UIUtil.isRetina()) {
myImage = myImage.getSubimage(0, 0, width / 2, height / 2);
}
myImage.setData(raster);
byte[] bytes = imageToByteArray(myImage);
if (bytes == null) return;
ApplicationManager.getApplication().invokeLater(() -> {
ApplicationManager.getApplication().runWriteAction(() -> {
try {
setBinaryContent(bytes);
}
catch (IOException ignored) {
}
});
});
}
public BufferedImage getImage() {
return myImage;
}
public static byte[] imageToByteArray(BufferedImage image) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
try {
ImageIO.write(image, PyPlotToolWindow.PLOT_FORMAT, stream);
stream.flush();
byte[] imageInByte = stream.toByteArray();
stream.close();
return imageInByte;
}
catch (IOException e) {
LOG.warn("Failed to convert image to byte array " + e.getMessage());
}
return null;
}
}
@@ -0,0 +1,28 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.python.run;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
public interface PythonCommandLineEnvironmentProvider {
ExtensionPointName<PythonCommandLineEnvironmentProvider> EP_NAME =
ExtensionPointName.create("Pythonid.pythonCommandLineEnvironmentProvider");
void extendEnvironment(@NotNull Project project, @NotNull GeneralCommandLine cmdLine);
}
@@ -36,6 +36,7 @@ import com.intellij.execution.ui.ConsoleView;
import com.intellij.facet.Facet;
import com.intellij.facet.FacetManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.module.ModuleUtilCore;
@@ -54,7 +55,6 @@ import com.intellij.openapi.vfs.encoding.EncodingProjectManager;
import com.intellij.remote.RemoteProcessControl;
import com.intellij.util.PlatformUtils;
import com.jetbrains.python.PythonHelpersLocator;
import com.jetbrains.python.actions.PySciProjectComponent;
import com.jetbrains.python.console.PyDebugConsoleBuilder;
import com.jetbrains.python.debugger.PyDebugRunner;
import com.jetbrains.python.debugger.PyDebuggerOptionsProvider;
@@ -325,10 +325,6 @@ public abstract class PythonCommandLineState extends CommandLineState {
if (myConfig.getEnvs() != null) {
env.putAll(myConfig.getEnvs());
}
if (PySciProjectComponent.getInstance(project).matplotlibInToolwindow() &&
PySciProjectComponent.getInstance(project).getPort() != -1) {
env.put("PYCHARM_MATPLOTLIB_PORT", String.valueOf(PySciProjectComponent.getInstance(project).getPort()));
}
addCommonEnvironmentVariables(getInterpreterPath(project, myConfig), env);
setupVirtualEnvVariables(myConfig, env, myConfig.getSdkHome());
@@ -337,8 +333,11 @@ public abstract class PythonCommandLineState extends CommandLineState {
commandLine.getEnvironment().putAll(env);
commandLine.withParentEnvironmentType(myConfig.isPassParentEnvs() ? ParentEnvironmentType.CONSOLE : ParentEnvironmentType.NONE);
buildPythonPath(project, commandLine, myConfig, isDebug);
for (PythonCommandLineEnvironmentProvider envProvider : Extensions.getExtensions(PythonCommandLineEnvironmentProvider.EP_NAME)) {
envProvider.extendEnvironment(project, commandLine);
}
}
private static void setupVirtualEnvVariables(PythonRunParams myConfig, Map<String, String> env, String sdkHome) {
@@ -385,10 +384,6 @@ public abstract class PythonCommandLineState extends CommandLineState {
Sdk pythonSdk = PythonSdkType.findSdkByPath(config.getSdkHome());
if (pythonSdk != null) {
List<String> pathList = Lists.newArrayList();
if (PySciProjectComponent.getInstance(project).matplotlibInToolwindow() &&
PySciProjectComponent.getInstance(project).getPort() != -1) {
pathList.add(PythonHelpersLocator.getHelperPath("pycharm_matplotlib_backend"));
}
pathList.addAll(getAddedPaths(pythonSdk));
pathList.addAll(collectPythonPath(project, config, isDebug));
initPythonPath(commandLine, config.isPassParentEnvs(), pathList, config.getSdkHome());