extract community part out of python-ide module

This commit is contained in:
Dmitry Jemerov
2013-08-30 18:51:58 +02:00
parent 9ac5a475dc
commit d44732de3a
40 changed files with 3524 additions and 2 deletions
+18
View File
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<module 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="platform-impl" />
<orderEntry type="module" module-name="python-community" />
<orderEntry type="module" module-name="lang-api" />
<orderEntry type="module" module-name="lang-impl" />
<orderEntry type="library" name="Guava" level="project" />
<orderEntry type="module" module-name="xml-psi-impl" />
</component>
</module>
@@ -0,0 +1,21 @@
package com.jetbrains.python;
import com.intellij.ide.util.projectWizard.EmptyModuleBuilder;
import com.intellij.openapi.module.ModuleType;
import org.jetbrains.annotations.NotNull;
/**
* @author yole
*/
public class PlatformPythonModuleType extends PythonModuleTypeBase<EmptyModuleBuilder> {
@NotNull
@Override
public EmptyModuleBuilder createModuleBuilder() {
return new EmptyModuleBuilder() {
@Override
public ModuleType getModuleType() {
return getInstance();
}
};
}
}
@@ -0,0 +1,79 @@
package com.jetbrains.python;
import com.intellij.application.options.InitialConfigurationDialog;
import com.intellij.codeInsight.CodeInsightSettings;
import com.intellij.ide.AppLifecycleListener;
import com.intellij.ide.OpenJdkNotifier;
import com.intellij.ide.ui.UISettings;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.ex.EditorSettingsExternalizable;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.util.messages.MessageBus;
import com.jetbrains.python.codeInsight.PyCodeInsightSettings;
import org.jetbrains.annotations.NonNls;
import javax.swing.*;
/**
* @author yole
*/
@SuppressWarnings({"UtilityClassWithoutPrivateConstructor", "UtilityClassWithPublicConstructor"})
public class PyCharmInitialConfigurator {
@NonNls private static final String DISPLAYED_PROPERTY = "PyCharm.initialConfigurationShown";
public PyCharmInitialConfigurator(MessageBus bus, final PropertiesComponent propertiesComponent, final FileTypeManager fileTypeManager) {
OpenJdkNotifier.checkJdk(bus);
if (!propertiesComponent.getBoolean("PyCharm.InitialConfiguration", false)) {
propertiesComponent.setValue("PyCharm.InitialConfiguration", "true");
EditorSettingsExternalizable.getInstance().setVirtualSpace(false);
}
if (!propertiesComponent.getBoolean("PyCharm.InitialConfiguration.V2", false)) {
propertiesComponent.setValue("PyCharm.InitialConfiguration.V2", "true");
final CodeStyleSettings settings = CodeStyleSettingsManager.getInstance().getCurrentSettings();
settings.ALIGN_MULTILINE_PARAMETERS_IN_CALLS = true;
settings.getCommonSettings(PythonLanguage.getInstance()).ALIGN_MULTILINE_PARAMETERS_IN_CALLS = true;
UISettings.getInstance().SHOW_DIRECTORY_FOR_NON_UNIQUE_FILENAMES = true;
}
if (!propertiesComponent.getBoolean("PyCharm.InitialConfiguration.V3", false)) {
propertiesComponent.setValue("PyCharm.InitialConfiguration.V3", "true");
UISettings.getInstance().SHOW_MEMORY_INDICATOR = false;
final String ignoredFilesList = fileTypeManager.getIgnoredFilesList();
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
FileTypeManager.getInstance().setIgnoredFilesList(ignoredFilesList + ";*$py.class");
}
});
}
if (!propertiesComponent.getBoolean("PyCharm.InitialConfiguration.V4", false)) {
propertiesComponent.setValue("PyCharm.InitialConfiguration.V4", "true");
PyCodeInsightSettings.getInstance().SHOW_IMPORT_POPUP = false;
}
if (!propertiesComponent.getBoolean("PyCharm.InitialConfiguration.V5", false)) {
propertiesComponent.setValue("PyCharm.InitialConfiguration.V5", "true");
CodeInsightSettings.getInstance().REFORMAT_ON_PASTE = CodeInsightSettings.NO_REFORMAT;
}
if (!propertiesComponent.isValueSet(DISPLAYED_PROPERTY)) {
bus.connect().subscribe(AppLifecycleListener.TOPIC, new AppLifecycleListener.Adapter() {
@Override
public void welcomeScreenDisplayed() {
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
propertiesComponent.setValue(DISPLAYED_PROPERTY, "true");
showInitialConfigurationDialog();
}
});
}
});
}
}
private static void showInitialConfigurationDialog() {
final JFrame frame = WindowManager.getInstance().findVisibleFrame();
new InitialConfigurationDialog(frame, "Python").show();
}
}
@@ -0,0 +1,128 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.jetbrains.python.PyIdeCommonOptionsForm">
<grid id="464af" binding="myHideablePanel" layout-manager="BorderLayout" hgap="0" vgap="0">
<constraints>
<xy x="20" y="20" width="522" height="400"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<grid id="27dc6" binding="myMainPanel" layout-manager="GridLayoutManager" row-count="10" 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 border-constraint="Center"/>
<properties/>
<border type="none"/>
<children>
<vspacer id="a7e1d">
<constraints>
<grid row="9" 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>
<component id="62f63" class="javax.swing.JLabel">
<constraints>
<grid row="3" 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 value="&amp;Interpreter options:"/>
</properties>
</component>
<component id="47414" class="com.intellij.ui.RawCommandLineEditor" binding="myInterpreterOptionsTextField">
<constraints>
<grid row="3" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="7" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<dialogCaption value="Enter interpreter options"/>
</properties>
</component>
<component id="32056" class="javax.swing.JLabel">
<constraints>
<grid row="4" 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 value="&amp;Working directory:"/>
</properties>
</component>
<component id="a0dd" class="com.intellij.openapi.ui.TextFieldWithBrowseButton" binding="myWorkingDirectoryTextField">
<constraints>
<grid row="4" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
</component>
<component id="58eee" class="com.intellij.ui.components.JBLabel" binding="myPythonInterpreterJBLabel">
<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>
<labelFor value="39bcf"/>
<text value="&amp;Python interpreter:"/>
</properties>
</component>
<component id="39bcf" class="javax.swing.JComboBox" binding="myInterpreterComboBox" custom-create="true">
<constraints>
<grid row="2" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
</component>
<component id="a0aae" class="com.intellij.execution.configuration.EnvironmentVariablesComponent" binding="myEnvsComponent">
<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>
<labelLocation value="West"/>
<text value="&amp;Environment variables"/>
</properties>
</component>
<component id="fec2b" class="javax.swing.JLabel" binding="myProjectLabel">
<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 value="Pro&amp;ject:"/>
</properties>
</component>
<component id="195cd" class="javax.swing.JComboBox" binding="myModuleCombo">
<constraints>
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
</component>
<grid id="ded2d" binding="myConfigureInterpretersPanel" layout-manager="BorderLayout" hgap="0" vgap="0">
<constraints>
<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"/>
<children/>
</grid>
<component id="c633e" class="com.intellij.execution.util.PathMappingsComponent" binding="myPathMappingsComponent">
<constraints>
<grid row="5" 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>
<labelLocation value="West"/>
<text value="Path mappings"/>
</properties>
</component>
<component id="7ebfd" class="com.intellij.ui.components.JBCheckBox" binding="myAddContentRootsCheckbox">
<constraints>
<grid row="7" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<selected value="true"/>
<text value="Add content roots to PYTHONPATH"/>
</properties>
</component>
<component id="507b" class="com.intellij.ui.components.JBCheckBox" binding="myAddSourceRootsCheckbox">
<constraints>
<grid row="8" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<selected value="true"/>
<text value="Add source roots to PYTHONPATH"/>
</properties>
</component>
</children>
</grid>
</children>
</grid>
</form>
@@ -0,0 +1,352 @@
package com.jetbrains.python;
import com.intellij.execution.configuration.EnvironmentVariablesComponent;
import com.intellij.execution.util.PathMappingsComponent;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.SdkModel;
import com.intellij.openapi.projectRoots.impl.SdkListCellRenderer;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel;
import com.intellij.openapi.ui.ComboBox;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.CollectionComboBoxModel;
import com.intellij.ui.HideableDecorator;
import com.intellij.ui.RawCommandLineEditor;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.ui.components.JBLabel;
import com.intellij.util.PathMappingSettings;
import com.jetbrains.python.configuration.PyConfigurableInterpreterList;
import com.jetbrains.python.configuration.PyConfigureInterpretersLinkPanel;
import com.jetbrains.python.run.AbstractPyCommonOptionsForm;
import com.intellij.application.options.ModuleListCellRenderer;
import com.jetbrains.python.run.PyCommonOptionsFormData;
import com.jetbrains.python.sdk.PySdkUtil;
import com.jetbrains.python.sdk.PythonSdkType;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author yole
*/
public class PyIdeCommonOptionsForm implements AbstractPyCommonOptionsForm {
private JPanel myMainPanel;
private EnvironmentVariablesComponent myEnvsComponent;
private RawCommandLineEditor myInterpreterOptionsTextField;
private TextFieldWithBrowseButton myWorkingDirectoryTextField;
private JComboBox myInterpreterComboBox;
private JBLabel myPythonInterpreterJBLabel;
private JLabel myProjectLabel;
private JComboBox myModuleCombo;
private JPanel myConfigureInterpretersPanel;
private String mySelectedSdkHome = null;
private PathMappingsComponent myPathMappingsComponent;
private JPanel myHideablePanel;
private JBCheckBox myAddContentRootsCheckbox;
private JBCheckBox myAddSourceRootsCheckbox;
private JComponent labelAnchor;
private final Project myProject;
private List<Sdk> myPythonSdks;
private boolean myInterpreterRemote;
private final HideableDecorator myDecorator;
public PyIdeCommonOptionsForm(PyCommonOptionsFormData data) {
myProject = data.getProject();
myWorkingDirectoryTextField.addBrowseFolderListener("Select Working Directory", "", data.getProject(),
FileChooserDescriptorFactory.createSingleFolderDescriptor());
myPythonSdks = new ArrayList<Sdk>(PythonSdkType.getAllSdks());
myPythonSdks.add(0, null);
myInterpreterComboBox.setModel(new CollectionComboBoxModel(myPythonSdks, null));
final Module[] modules = ModuleManager.getInstance(data.getProject()).getModules();
if (modules.length == 1) {
setModule(modules[0]);
myProjectLabel.setVisible(false);
myModuleCombo.setVisible(false);
}
else {
final List<Module> validModules = data.getValidModules();
Module selection = validModules.size() > 0 ? validModules.get(0) : null;
myModuleCombo.setModel(new CollectionComboBoxModel(validModules, selection));
myModuleCombo.setRenderer(new ModuleListCellRenderer());
myModuleCombo.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
updateDefaultInterpreter((Module)myModuleCombo.getSelectedItem());
}
});
updateDefaultInterpreter((Module)myModuleCombo.getSelectedItem());
}
setAnchor(myEnvsComponent.getLabel());
myPathMappingsComponent.setAnchor(myEnvsComponent.getLabel());
if (data.showConfigureInterpretersLink()) {
myConfigureInterpretersPanel.add(new PyConfigureInterpretersLinkPanel(myMainPanel));
}
addInterpreterComboBoxActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
updateRemoteInterpreterMode();
}
}
);
updateRemoteInterpreterMode();
myDecorator = new HideableDecorator(myHideablePanel, "Environment", false) {
@Override
protected void on() {
super.on();
storeState();
}
@Override
protected void off() {
super.off();
storeState();
}
private void storeState() {
PropertiesComponent.getInstance().setValue(EXPAND_PROPERTY_KEY, String.valueOf(isExpanded()));
}
};
myDecorator.setOn(PropertiesComponent.getInstance().getBoolean(EXPAND_PROPERTY_KEY, true));
myDecorator.setContentComponent(myMainPanel);
}
@Override
public JComponent getMainPanel() {
return myHideablePanel;
}
@Override
public void subscribe() {
PyConfigurableInterpreterList myInterpreterList = PyConfigurableInterpreterList.getInstance(myProject);
ProjectSdksModel myProjectSdksModel = myInterpreterList.getModel();
myProjectSdksModel.addListener(new MyListener(this, myInterpreterList));
updateSdkList(true, myInterpreterList);
}
@Override
public JComponent getAnchor() {
return labelAnchor;
}
@Override
public void setAnchor(JComponent anchor) {
labelAnchor = anchor;
myEnvsComponent.setAnchor(anchor);
myPythonInterpreterJBLabel.setAnchor(anchor);
}
public String getInterpreterOptions() {
return myInterpreterOptionsTextField.getText().trim();
}
public void setInterpreterOptions(String interpreterOptions) {
myInterpreterOptionsTextField.setText(interpreterOptions);
}
public String getWorkingDirectory() {
return FileUtil.toSystemIndependentName(myWorkingDirectoryTextField.getText().trim());
}
public void setWorkingDirectory(String workingDirectory) {
myWorkingDirectoryTextField.setText(workingDirectory == null ? "" : FileUtil.toSystemDependentName(workingDirectory));
}
@Override
public String getSdkHome() {
final Sdk selectedSdk = (Sdk)myInterpreterComboBox.getSelectedItem();
return selectedSdk == null ? null : selectedSdk.getHomePath();
}
@Override
public void setSdkHome(String sdkHome) {
mySelectedSdkHome = sdkHome;
}
@Nullable
@Override
public Module getModule() {
final Module selectedItem = (Module)myModuleCombo.getSelectedItem();
if (selectedItem != null) {
return selectedItem;
}
final Module[] modules = ModuleManager.getInstance(myProject).getModules();
if (modules.length == 1) {
return modules[0];
}
return null;
}
@Override
public void setModule(Module module) {
myModuleCombo.setSelectedItem(module);
updateDefaultInterpreter(module);
}
private void updateDefaultInterpreter(Module module) {
final Sdk sdk = module == null ? null : ModuleRootManager.getInstance(module).getSdk();
String projectSdkName = sdk == null ? "none" : sdk.getName();
myInterpreterComboBox.setRenderer(new SdkListCellRenderer("Project Default (" + projectSdkName + ")"));
}
public void updateSdkList(boolean preserveSelection, PyConfigurableInterpreterList myInterpreterList) {
myPythonSdks = myInterpreterList.getAllPythonSdks();
Sdk selection = preserveSelection ? (Sdk)myInterpreterComboBox.getSelectedItem() : null;
if (!myPythonSdks.contains(selection)) {
selection = null;
}
myPythonSdks.add(0, null);
myInterpreterComboBox.setModel(new CollectionComboBoxModel(myPythonSdks, selection));
}
@Override
public boolean isUseModuleSdk() {
return myInterpreterComboBox.getSelectedItem() == null;
}
@Override
public void setUseModuleSdk(boolean useModuleSdk) {
myInterpreterComboBox.setSelectedItem(useModuleSdk ? null : PythonSdkType.findSdkByPath(myPythonSdks, mySelectedSdkHome));
}
public boolean isPassParentEnvs() {
return myEnvsComponent.isPassParentEnvs();
}
public void setPassParentEnvs(boolean passParentEnvs) {
myEnvsComponent.setPassParentEnvs(passParentEnvs);
}
public Map<String, String> getEnvs() {
return myEnvsComponent.getEnvs();
}
public void setEnvs(Map<String, String> envs) {
myEnvsComponent.setEnvs(envs);
}
@Override
@Nullable
public PathMappingSettings getMappingSettings() {
if (myInterpreterRemote) {
return myPathMappingsComponent.getMappingSettings();
}
else {
return null;
}
}
@Override
public void setMappingSettings(@Nullable PathMappingSettings mappingSettings) {
myPathMappingsComponent.setMappingSettings(mappingSettings);
}
@Override
public boolean addContentRoots() {
return myAddContentRootsCheckbox.isSelected();
}
@Override
public boolean addSourceRoots() {
return myAddSourceRootsCheckbox.isSelected();
}
@Override
public void addContentRoots(boolean add) {
myAddContentRootsCheckbox.setSelected(add);
}
@Override
public void addSourceRoots(boolean add) {
myAddSourceRootsCheckbox.setSelected(add);
}
private void createUIComponents() {
myInterpreterComboBox = new ComboBox(100);
}
private void setRemoteInterpreterMode(boolean isInterpreterRemote) {
myInterpreterRemote = isInterpreterRemote;
myPathMappingsComponent.setVisible(isInterpreterRemote);
}
private void updateRemoteInterpreterMode() {
setRemoteInterpreterMode(PySdkUtil.isRemote(getSdkSelected()));
}
@Nullable
private Sdk getSdkSelected() {
String sdkHome = getSdkHome();
if (StringUtil.isEmptyOrSpaces(sdkHome)) {
final Sdk projectJdk = PythonSdkType.findPythonSdk(getModule());
if (projectJdk != null) {
sdkHome = projectJdk.getHomePath();
}
}
return PythonSdkType.findSdkByPath(sdkHome);
}
@Override
public void addInterpreterComboBoxActionListener(ActionListener listener) {
myInterpreterComboBox.addActionListener(listener);
}
@Override
public void removeInterpreterComboBoxActionListener(ActionListener listener) {
myInterpreterComboBox.removeActionListener(listener);
}
private static class MyListener implements SdkModel.Listener {
private final PyIdeCommonOptionsForm myForm;
private PyConfigurableInterpreterList myInterpreterList;
public MyListener(PyIdeCommonOptionsForm form, PyConfigurableInterpreterList interpreterList) {
myForm = form;
myInterpreterList = interpreterList;
}
private void update() {
myForm.updateSdkList(true, myInterpreterList);
}
@Override
public void sdkAdded(Sdk sdk) {
update();
}
@Override
public void beforeSdkRemove(Sdk sdk) {
update();
}
@Override
public void sdkChanged(Sdk sdk, String previousName) {
update();
}
@Override
public void sdkHomeSelected(Sdk sdk, String newSdkHome) {
}
}
}
@@ -0,0 +1,15 @@
package com.jetbrains.python;
import com.jetbrains.python.run.AbstractPyCommonOptionsForm;
import com.jetbrains.python.run.PyCommonOptionsFormData;
import com.jetbrains.python.run.PyCommonOptionsFormFactory;
/**
* @author yole
*/
public class PyIdeCommonOptionsFormFactory extends PyCommonOptionsFormFactory {
@Override
public PyIdeCommonOptionsForm createForm(PyCommonOptionsFormData data) {
return new PyIdeCommonOptionsForm(data);
}
}
@@ -0,0 +1,36 @@
package com.jetbrains.python;
import com.intellij.ProjectTopics;
import com.intellij.execution.RunManagerEx;
import com.intellij.execution.RunnerAndConfigurationSettings;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.ModuleAdapter;
import com.intellij.openapi.project.Project;
import com.intellij.util.messages.MessageBus;
import com.jetbrains.python.run.AbstractPythonRunConfiguration;
import java.util.ArrayList;
import java.util.Collection;
/**
* @author yole
*/
public class PyModuleListener {
public PyModuleListener(MessageBus messageBus) {
messageBus.connect().subscribe(ProjectTopics.MODULES, new ModuleAdapter() {
@Override
public void beforeModuleRemoved(Project project, Module module) {
final RunManagerEx runManager = RunManagerEx.getInstanceEx(project);
final Collection<RunnerAndConfigurationSettings> configurations = new ArrayList<RunnerAndConfigurationSettings>(runManager.getSortedConfigurations());
for (RunnerAndConfigurationSettings configuration : configurations) {
if (configuration.getConfiguration() instanceof AbstractPythonRunConfiguration) {
final Module configModule = ((AbstractPythonRunConfiguration)configuration.getConfiguration()).getModule();
if (configModule == module) {
runManager.removeConfiguration(configuration);
}
}
}
}
});
}
}
@@ -0,0 +1,14 @@
package com.jetbrains.python;
import com.intellij.application.options.OptionId;
import com.intellij.application.options.OptionsApplicabilityFilter;
/**
* @author yole
*/
public class PyOptionsApplicabilityFilter extends OptionsApplicabilityFilter {
@Override
public boolean isOptionApplicable(OptionId optionId) {
return optionId == OptionId.RENAME_IN_PLACE;
}
}
@@ -0,0 +1,21 @@
package com.jetbrains.python;
import com.intellij.ide.highlighter.XmlFileType;
import com.intellij.openapi.fileTypes.FileTypeConsumer;
import com.intellij.openapi.fileTypes.FileTypeFactory;
import com.jetbrains.pyqt.QtUIFileType;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
/**
* IDE version of file type factory - does not use UltimateVerifier.
*
* @author yole
*/
public class PythonFileTypeFactory extends FileTypeFactory {
public void createFileTypes(@NonNls @NotNull final FileTypeConsumer consumer) {
consumer.consume(PythonFileType.INSTANCE, "py;pyw;");
consumer.consume(QtUIFileType.INSTANCE, "ui");
consumer.consume(XmlFileType.INSTANCE, "qrc");
}
}
@@ -0,0 +1,14 @@
package com.jetbrains.python;
import com.intellij.openapi.module.ModuleType;
import com.intellij.openapi.module.impl.ModuleTypeManagerImpl;
/**
* @author yole
*/
public class PythonModuleTypeManager extends ModuleTypeManagerImpl {
@Override
public ModuleType getDefaultModuleType() {
return new PlatformPythonModuleType();
}
}
@@ -0,0 +1,74 @@
package com.jetbrains.python;
import com.intellij.openapi.options.ShowSettingsUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.SdkType;
import com.intellij.openapi.projectRoots.impl.SdkListCellRenderer;
import com.intellij.openapi.util.Condition;
import com.intellij.ui.CollectionComboBoxModel;
import com.intellij.ui.ComboboxWithBrowseButton;
import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.configuration.PythonSdkConfigurable;
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
import com.jetbrains.python.sdk.PythonSdkType;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
/**
* @author yole
*/
public class PythonSdkChooserCombo extends ComboboxWithBrowseButton {
private final List<ActionListener> myChangedListeners = ContainerUtil.createLockFreeCopyOnWriteList();
//public PythonSdkChooserCombo(final Condition<Sdk> acceptableSdkCondition) {
// this(PythonSdkType.getAllSdks(), acceptableSdkCondition);
//}
public PythonSdkChooserCombo(final Project project, List<Sdk> sdks, final Condition<Sdk> acceptableSdkCondition) {
Sdk initialSelection = null;
for (Sdk sdk : sdks) {
if (acceptableSdkCondition.value(sdk)) {
initialSelection = sdk;
break;
}
}
getComboBox().setModel(new CollectionComboBoxModel(sdks, initialSelection));
getComboBox().setRenderer(new SdkListCellRenderer("<no interpreter>") {
@Override
protected Icon getSdkIcon(Sdk sdk) {
final PythonSdkFlavor flavor = PythonSdkFlavor.getFlavor(sdk);
return flavor != null ? flavor.getIcon() : ((SdkType)sdk.getSdkType()).getIcon();
}
});
addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
final PythonSdkConfigurable configurable = new PythonSdkConfigurable(project);
configurable.setNewProject(true);
ShowSettingsUtil.getInstance().editConfigurable(PythonSdkChooserCombo.this, configurable);
Sdk selection = configurable.getRealSelectedSdk();
final List<Sdk> sdks = PythonSdkType.getAllSdks();
getComboBox().setModel(new CollectionComboBoxModel(sdks, selection));
notifyChanged(e);
}
});
getComboBox().addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
notifyChanged(e);
}
});
}
private void notifyChanged(ActionEvent e) {
for (ActionListener changedListener : myChangedListeners) {
changedListener.actionPerformed(e);
}
}
public void addChangedListener(ActionListener listener) {
myChangedListeners.add(listener);
}
}
@@ -0,0 +1,79 @@
package com.jetbrains.python;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.SdkAdditionalData;
import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl;
import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.platform.DirectoryProjectConfigurator;
import com.intellij.util.SystemProperties;
import com.jetbrains.python.sdk.PreferredSdkComparator;
import com.jetbrains.python.sdk.PythonSdkAdditionalData;
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
import com.jetbrains.python.sdk.PythonSdkType;
import com.jetbrains.python.sdk.flavors.VirtualEnvSdkFlavor;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* @author dcheryasov
*/
public class PythonSdkConfigurator implements DirectoryProjectConfigurator {
public void configureProject(final Project project, @NotNull final VirtualFile baseDir, Ref<Module> moduleRef) {
// it it a virtualenv?
final PythonSdkType py_sdk_type = PythonSdkType.getInstance();
//find virtualEnv in project directory
final List<String> candidates = new ArrayList<String>();
if (project != null) {
final VirtualFile rootDir = project.getBaseDir();
if (rootDir != null)
candidates.addAll(VirtualEnvSdkFlavor.findInDirectory(rootDir));
if (!candidates.isEmpty()) {
String filePath = candidates.get(0);
if (StringUtil.startsWithChar(filePath, '~')) {
final String home = SystemProperties.getUserHome();
filePath = home + filePath.substring(1);
}
final Sdk virtualEnvSdk = SdkConfigurationUtil.createAndAddSDK(filePath, py_sdk_type);
if (virtualEnvSdk != null) {
SdkConfigurationUtil.setDirectoryProjectSdk(project, virtualEnvSdk);
SdkAdditionalData additionalData = virtualEnvSdk.getSdkAdditionalData();
if (additionalData == null) {
additionalData = new PythonSdkAdditionalData(PythonSdkFlavor.getFlavor(virtualEnvSdk.getHomePath()));
((ProjectJdkImpl)virtualEnvSdk).setSdkAdditionalData(additionalData);
}
((PythonSdkAdditionalData) additionalData).associateWithProject(project);
return;
}
return;
}
}
final Sdk existing_sdk = ProjectRootManager.getInstance(project).getProjectSdk();
if (existing_sdk != null && existing_sdk.getSdkType() == py_sdk_type) return; // SdkConfigurationUtil does the same
final File py_exe = PythonSdkType.findExecutableFile(new File(project.getBasePath(), "bin"), "python");
if (py_exe != null) {
final File env_root = PythonSdkType.getVirtualEnvRoot(py_exe.getPath());
if (env_root != null) {
// yes, an unknown virtualenv; set it up as SDK
final Sdk an_sdk = SdkConfigurationUtil.createAndAddSDK(py_exe.getPath(), py_sdk_type);
if (an_sdk != null) {
SdkConfigurationUtil.setDirectoryProjectSdk(project, an_sdk);
return;
}
}
}
// default
SdkConfigurationUtil.configureDirectoryProjectSdk(project, new PreferredSdkComparator(), py_sdk_type);
}
}
@@ -0,0 +1,104 @@
package com.jetbrains.python;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ContentEntry;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.SourceFolder;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.platform.DirectoryProjectConfigurator;
import com.intellij.psi.PsiFileFactory;
import com.jetbrains.python.psi.*;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
/**
* @author yole
*/
public class PythonSourceRootConfigurator implements DirectoryProjectConfigurator {
@NonNls private static final String SETUP_PY = "setup.py";
@Override
public void configureProject(Project project, @NotNull final VirtualFile baseDir, Ref<Module> moduleRef) {
VirtualFile setupPy = baseDir.findChild(SETUP_PY);
if (setupPy != null) {
final CharSequence content = LoadTextUtil.loadText(setupPy);
PyFile setupPyFile = (PyFile) PsiFileFactory.getInstance(project).createFileFromText(SETUP_PY, content.toString());
final SetupCallVisitor visitor = new SetupCallVisitor();
setupPyFile.accept(visitor);
String dir = visitor.getRootPackageDir();
if (dir != null) {
final VirtualFile rootPackageVFile = baseDir.findFileByRelativePath(dir);
addSourceRoot(project, baseDir, rootPackageVFile, true);
}
}
VirtualFile web2Py = baseDir.findChild("web2py");
if (web2Py != null) {
addSourceRoot(project, baseDir, web2Py, false);
}
}
private static void addSourceRoot(Project project, final VirtualFile baseDir, final VirtualFile root, final boolean unique) {
final Module[] modules = ModuleManager.getInstance(project).getModules();
if (modules.length > 0 && root != null) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
final ModifiableRootModel model = ModuleRootManager.getInstance(modules[0]).getModifiableModel();
final ContentEntry[] contentEntries = model.getContentEntries();
for (ContentEntry contentEntry : contentEntries) {
if (Comparing.equal(contentEntry.getFile(), baseDir)) {
final SourceFolder[] sourceFolders = contentEntry.getSourceFolders();
if (!unique || sourceFolders.length == 0) {
contentEntry.addSourceFolder(root, false);
}
}
}
model.commit();
}
});
}
}
private static class SetupCallVisitor extends PyRecursiveElementVisitor {
private String myRootPackageDir = null;
@Override
public void visitPyCallExpression(PyCallExpression node) {
final PyArgumentList argList = node.getArgumentList();
if (node.isCalleeText("setup") && argList != null) {
final PyKeywordArgument packageDirArg = argList.getKeywordArgument("package_dir");
if (packageDirArg != null) {
final PyExpression valueExpression = packageDirArg.getValueExpression();
if (valueExpression instanceof PyDictLiteralExpression) {
PyDictLiteralExpression packageDirDict = (PyDictLiteralExpression)valueExpression;
for (PyKeyValueExpression keyValue : packageDirDict.getElements()) {
final PyExpression keyExpr = keyValue.getKey();
final PyExpression valueExpr = keyValue.getValue();
if (keyExpr instanceof PyStringLiteralExpression && valueExpr instanceof PyStringLiteralExpression) {
String key = ((PyStringLiteralExpression) keyExpr).getStringValue();
String value = ((PyStringLiteralExpression)valueExpr).getStringValue();
if (key.length() == 0) {
myRootPackageDir = value;
}
}
}
}
}
}
else {
super.visitPyCallExpression(node);
}
}
public String getRootPackageDir() {
return myRootPackageDir;
}
}
}
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.jetbrains.python.buildout.BuildoutConfigurable">
<grid id="27dc6" binding="myMainPanel" layout-manager="BorderLayout" hgap="0" vgap="0">
<constraints>
<xy x="20" y="20" width="541" height="400"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<grid id="9337d" 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 border-constraint="North"/>
<properties/>
<border type="none"/>
<children>
<component id="287e6" class="javax.swing.JCheckBox" binding="myEnabledCheckbox">
<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>
<enabled value="false"/>
<text value="&amp;Enable buildout support"/>
</properties>
</component>
</children>
</grid>
<grid id="88f56" binding="myPlaceholder" layout-manager="BorderLayout" hgap="0" vgap="0">
<constraints border-constraint="Center"/>
<properties/>
<border type="none"/>
<children/>
</grid>
</children>
</grid>
</form>
@@ -0,0 +1,171 @@
package com.jetbrains.python.buildout;
import com.intellij.facet.FacetManager;
import com.intellij.facet.ModifiableFacetModel;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.NonDefaultProjectConfigurable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.util.List;
/**
* A silly configurable to add buildout facet configurator to PyCharm
* User: dcheryasov
* Date: Jul 28, 2010 4:34:58 PM
*/
public class BuildoutConfigurable implements Configurable, NonDefaultProjectConfigurable {
private JCheckBox myEnabledCheckbox;
private JPanel myPlaceholder;
private JPanel myMainPanel;
private BuildoutConfigPanel mySettingsPanel;
private final Module myModule;
public BuildoutConfigurable(@NotNull Module module) {
myModule = module;
BuildoutFacetConfiguration config = null;
BuildoutFacet facet = BuildoutFacet.getInstance(myModule);
if (facet != null) config = facet.getConfiguration();
if (config == null) config = new BuildoutFacetConfiguration(null);
mySettingsPanel = new BuildoutConfigPanel(myModule, config);
myPlaceholder.add(mySettingsPanel, BorderLayout.CENTER);
final boolean isEnabled = !StringUtil.isEmptyOrSpaces(config.getScriptName());
myEnabledCheckbox.setSelected(isEnabled);
updateFacetEnabled(isEnabled);
myEnabledCheckbox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
final boolean enabled = myEnabledCheckbox.isSelected();
updateFacetEnabled(enabled);
}
});
mySettingsPanel.addFocusListener(
new FocusListener() {
@Override
public void focusGained(FocusEvent focusEvent) {
switchNoticeText();
}
@Override
public void focusLost(FocusEvent focusEvent) { }
}
);
}
private void updateFacetEnabled(boolean enabled) {
mySettingsPanel.setFacetEnabled(enabled);
UIUtil.setEnabled(mySettingsPanel, enabled, true);
}
@Nls
@Override
public String getDisplayName() {
return "Buildout Support";
}
@Override
public String getHelpTopic() {
return "reference-python-buildout";
}
@Override
public JComponent createComponent() {
switchNoticeText();
return myMainPanel;
}
@Override
public boolean isModified() {
if (! myEnabledCheckbox.isEnabled()) return false;
final BuildoutFacet facet = myModule != null? BuildoutFacet.getInstance(myModule) : null;
final boolean got_facet = facet != null;
if (myEnabledCheckbox.isSelected() != got_facet) return true;
if (got_facet && myEnabledCheckbox.isSelected()) {
return mySettingsPanel.isModified(facet.getConfiguration());
}
return false;
}
@Override
public void apply() throws ConfigurationException {
final BuildoutFacet facet = myModule != null? BuildoutFacet.getInstance(myModule) : null;
final boolean got_facet = facet != null;
boolean facet_is_desired = myEnabledCheckbox.isSelected();
mySettingsPanel.apply();
List<String> paths_from_script = null;
if (facet_is_desired) {
String script_name = mySettingsPanel.getScriptName();
VirtualFile script_file = BuildoutConfigPanel.getScriptFile(script_name);
paths_from_script = BuildoutFacet.extractBuildoutPaths(script_file);
if (paths_from_script == null) {
throw new ConfigurationException("Failed to extract paths from '" + script_file.getPresentableName() + "'");
}
mySettingsPanel.getConfiguration().setPaths(paths_from_script);
}
if (facet_is_desired && ! got_facet) addFacet(mySettingsPanel.getConfiguration());
if (! facet_is_desired && got_facet) removeFacet(facet);
if (facet_is_desired) BuildoutFacet.attachLibrary(myModule);
else BuildoutFacet.detachLibrary(myModule);
}
private void addFacet(BuildoutFacetConfiguration config) {
BuildoutFacetConfigurator.setupFacet(myModule, config);
}
private void removeFacet(BuildoutFacet facet) {
final ModifiableFacetModel model = FacetManager.getInstance(myModule).createModifiableModel();
model.removeFacet(facet);
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
model.commit();
}
});
}
@Override
public void reset() {
// TODO: refactor, see AppEngineConfigurable
if (myModule == null) {
myEnabledCheckbox.setSelected(false);
myEnabledCheckbox.setEnabled(false);
}
else {
myEnabledCheckbox.setEnabled(true);
switchNoticeText();
final BuildoutFacet instance = BuildoutFacet.getInstance(myModule);
if (instance != null) {
boolean selected = ! StringUtil.isEmptyOrSpaces(instance.getConfiguration().getScriptName());
myEnabledCheckbox.setSelected(selected);
mySettingsPanel.setEnabled(selected);
mySettingsPanel.reset();
}
else {
myEnabledCheckbox.setSelected(false);
mySettingsPanel.setEnabled(false);
}
}
}
private void switchNoticeText() {
mySettingsPanel.showNoticeText(/*DjangoFacet.getInstance(myModule) != null*/ false);
}
@Override
public void disposeUIResources() {
}
}
@@ -0,0 +1,63 @@
package com.jetbrains.python.buildout;
import com.intellij.facet.FacetManager;
import com.intellij.facet.ModifiableFacetModel;
import com.intellij.facet.ProjectFacetManager;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.platform.DirectoryProjectConfigurator;
import org.jetbrains.annotations.NotNull;
import java.io.File;
/**
* Detects and configures a buildout facet.
* User: dcheryasov
* Date: Jul 26, 2010 6:10:39 PM
*/
public class BuildoutFacetConfigurator implements DirectoryProjectConfigurator {
@Override
public void configureProject(Project project, @NotNull VirtualFile baseDir, Ref<Module> moduleRef) {
final Module[] modules = ModuleManager.getInstance(project).getModules();
if (modules.length > 0) {
final Module module = modules[0];
if (BuildoutFacet.getInstance(module) == null) {
baseDir.refresh(false, false);
final VirtualFile runner = BuildoutFacet.getRunner(baseDir);
if (runner != null) {
// TODO parse buildout.cfg and find out the part to use for the default script
final File script = BuildoutFacet.findScript(null, "buildout", project.getBaseDir());
if (script != null) {
final ProjectFacetManager facetManager = ProjectFacetManager.getInstance(module.getProject());
final BuildoutFacetConfiguration config = facetManager.createDefaultConfiguration(BuildoutFacetType.getInstance());
config.setScriptName(script.getPath());
setupFacet(module, config);
}
}
}
}
}
static void setupFacet(Module module, @NotNull BuildoutFacetConfiguration config) {
//TODO: refactor, see other python facets
FacetManager facetManager = FacetManager.getInstance(module);
final ModifiableFacetModel model = facetManager.createModifiableModel();
BuildoutFacetType facetType = BuildoutFacetType.getInstance();
BuildoutFacet facet = facetManager.createFacet(facetType, facetType.getDefaultFacetName(), config, null);
model.addFacet(facet);
new WriteAction() {
protected void run(final Result result) throws Throwable {
model.commit();
}
}.execute();
facet.updatePaths();
BuildoutFacet.attachLibrary(module);
}
}
@@ -0,0 +1,23 @@
package com.jetbrains.python.buildout;
import com.intellij.application.options.ModuleAwareProjectConfigurable;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.NonDefaultProjectConfigurable;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
/**
* @author yole
*/
public class BuildoutModulesConfigurable extends ModuleAwareProjectConfigurable implements NonDefaultProjectConfigurable {
public BuildoutModulesConfigurable(Project project) {
super(project, "Buildout Support", "reference-python-buildout");
}
@NotNull
@Override
protected Configurable createModuleConfigurable(Module module) {
return new BuildoutConfigurable(module);
}
}
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.jetbrains.python.configuration.AddVEnvOptionsDialog">
<grid id="27dc6" binding="myMainPanel" layout-manager="GridLayoutManager" 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="20" y="20" width="500" height="400"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<component id="6ea43" class="com.intellij.ui.components.JBCheckBox" binding="myUseForThisProjectJBCheckBox" default-binding="true">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<selected value="true"/>
<text value="Set as project interpreter for &amp;this project"/>
</properties>
</component>
<vspacer id="46c2b">
<constraints>
<grid row="2" 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>
<component id="b3884" class="com.intellij.ui.components.JBCheckBox" binding="myMakeAvailableToAllJBCheckBox" default-binding="true">
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Make available to &amp;all projects"/>
</properties>
</component>
</children>
</grid>
</form>
@@ -0,0 +1,35 @@
package com.jetbrains.python.configuration;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.ui.components.JBCheckBox;
import javax.swing.*;
import java.awt.*;
/**
* @author yole
*/
public class AddVEnvOptionsDialog extends DialogWrapper {
private JBCheckBox myUseForThisProjectJBCheckBox;
private JBCheckBox myMakeAvailableToAllJBCheckBox;
private JPanel myMainPanel;
public AddVEnvOptionsDialog(Component parent) {
super(parent, false);
init();
setTitle("Add Virtualenv");
}
@Override
protected JComponent createCenterPanel() {
return myMainPanel;
}
public boolean useForThisProject() {
return myUseForThisProjectJBCheckBox.isSelected();
}
public boolean makeAvailableToAll() {
return myMakeAvailableToAllJBCheckBox.isSelected();
}
}
@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.jetbrains.python.configuration.EditSdkDialog">
<grid id="27dc6" binding="myMainPanel" layout-manager="GridLayoutManager" row-count="5" 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="600" height="400"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<component id="a965b" 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>
<labelFor value="bc0d9"/>
<text value="&amp;Name:"/>
</properties>
</component>
<vspacer id="41b5e">
<constraints>
<grid row="4" 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>
<component id="bc0d9" class="javax.swing.JTextField" binding="myNameTextField">
<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="300" height="-1"/>
</grid>
</constraints>
<properties>
<columns value="100"/>
</properties>
</component>
<component id="f30dd" class="javax.swing.JLabel">
<constraints>
<grid row="1" 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 value="&amp;Interpreter path:"/>
</properties>
</component>
<component id="f2225" class="com.intellij.openapi.ui.TextFieldWithBrowseButton" binding="myInterpreterPathTextField">
<constraints>
<grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
</component>
<component id="6478c" class="com.intellij.ui.components.JBCheckBox" binding="myAssociateCheckbox">
<constraints>
<grid row="2" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<selected value="false"/>
<text value="&amp;Associate this virtual environment with current project"/>
</properties>
</component>
<component id="8ba78" class="com.intellij.ui.components.JBLabel" binding="myRemoveAssociationLabel">
<constraints>
<grid row="3" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="2" use-parent-layout="false"/>
</constraints>
<properties>
<text value="&lt;html&gt;&lt;a href=&quot;#&quot;&gt;Remove association&lt;/a&gt;"/>
<visible value="true"/>
</properties>
</component>
</children>
</grid>
</form>
@@ -0,0 +1,106 @@
package com.jetbrains.python.configuration;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.SdkModificator;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.ui.ClickListener;
import com.intellij.ui.DocumentAdapter;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.ui.components.JBLabel;
import com.intellij.util.NullableFunction;
import com.jetbrains.python.sdk.PythonSdkAdditionalData;
import com.jetbrains.python.sdk.PythonSdkType;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import java.awt.event.MouseEvent;
/**
* @author yole
*/
public class EditSdkDialog extends DialogWrapper {
private JPanel myMainPanel;
private JTextField myNameTextField;
private TextFieldWithBrowseButton myInterpreterPathTextField;
private JBCheckBox myAssociateCheckbox;
private JBLabel myRemoveAssociationLabel;
private final boolean myWasAssociated;
private boolean myAssociationRemoved = false;
protected EditSdkDialog(Project project, SdkModificator sdk, final NullableFunction<String, String> nameValidator) {
super(project, true);
setTitle("Edit Python Interpreter");
myNameTextField.setText(sdk.getName());
myNameTextField.getDocument().addDocumentListener(new DocumentAdapter() {
@Override
protected void textChanged(DocumentEvent e) {
String nameError = nameValidator.fun(getName());
setErrorText(nameError);
setOKActionEnabled(nameError == null);
}
});
myInterpreterPathTextField.setText(sdk.getHomePath());
myInterpreterPathTextField.addBrowseFolderListener("Specify Interpreter Path", null, project,
PythonSdkType.getInstance().getHomeChooserDescriptor());
myRemoveAssociationLabel.setVisible(false);
if (PythonSdkType.getVirtualEnvRoot(sdk.getHomePath()) == null) {
myAssociateCheckbox.setVisible(false);
}
else {
PythonSdkAdditionalData data = (PythonSdkAdditionalData) sdk.getSdkAdditionalData();
if (data != null) {
final String path = data.getAssociatedProjectPath();
if (path != null) {
myAssociateCheckbox.setSelected(true);
final String basePath = project.getBasePath();
if (basePath != null && !path.equals(FileUtil.toSystemIndependentName(basePath))) {
myAssociateCheckbox.setEnabled(false);
myAssociateCheckbox.setText("Associate this virtual environment with " + FileUtil.toSystemDependentName(path));
myRemoveAssociationLabel.setVisible(true);
}
}
}
}
myWasAssociated = myAssociateCheckbox.isSelected();
init();
new ClickListener() {
@Override
public boolean onClick(MouseEvent e, int clickCount) {
myAssociateCheckbox.setSelected(false);
myAssociateCheckbox.setEnabled(true);
myAssociateCheckbox.setText("Associate this environment with current project");
myRemoveAssociationLabel.setVisible(false);
myAssociationRemoved = true;
return true;
}
}.installOn(myRemoveAssociationLabel);
}
@Override
protected JComponent createCenterPanel() {
return myMainPanel;
}
@Override
public JComponent getPreferredFocusedComponent() {
return myNameTextField;
}
public String getName() {
return myNameTextField.getText();
}
public String getHomePath() {
return myInterpreterPathTextField.getText();
}
public boolean associateWithProject() {
return myAssociateCheckbox.isSelected();
}
public boolean isAssociateChanged() {
return myWasAssociated != associateWithProject() || myAssociationRemoved;
}
}
@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.jetbrains.python.configuration.PyActiveSdkConfigurable">
<grid id="27dc6" 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="20" y="20" width="500" height="400"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<component id="70598" 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="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Project Interpreter:"/>
</properties>
</component>
<vspacer id="3aae9">
<constraints>
<grid row="2" 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>
<component id="7421c" class="javax.swing.JComboBox" binding="mySdkCombo">
<constraints>
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
</component>
<grid id="19f49" binding="myConfigureInterpretersPanel" layout-manager="BorderLayout" hgap="0" vgap="0">
<constraints>
<grid row="1" 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/>
</grid>
</children>
</grid>
</form>
@@ -0,0 +1,203 @@
package com.jetbrains.python.configuration;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.highlighter.EditorHighlighter;
import com.intellij.openapi.editor.highlighter.EditorHighlighterFactory;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.UnnamedConfigurable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.SdkModel;
import com.intellij.openapi.projectRoots.impl.SdkListCellRenderer;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.ModuleRootModificationUtil;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.CollectionComboBoxModel;
import com.jetbrains.python.psi.LanguageLevel;
import com.jetbrains.python.sdk.PySdkListCellRenderer;
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.util.List;
/**
* @author yole
*/
public class PyActiveSdkConfigurable implements UnnamedConfigurable {
private JPanel myPanel;
private final Project myProject;
@Nullable private final Module myModule;
private JComboBox mySdkCombo;
private JPanel myConfigureInterpretersPanel;
private PyConfigurableInterpreterList myInterpreterList;
private ProjectSdksModel myProjectSdksModel;
private MyListener myListener;
public PyActiveSdkConfigurable(Project project) {
myModule = null;
myProject = project;
init();
}
public PyActiveSdkConfigurable(@NotNull Module module) {
myModule = module;
myProject = module.getProject();
init();
}
private void init() {
mySdkCombo.setRenderer(new SdkListCellRenderer("<None>"));
myInterpreterList = PyConfigurableInterpreterList.getInstance(myProject);
myProjectSdksModel = myInterpreterList.getModel();
myListener = new MyListener(this);
myProjectSdksModel.addListener(myListener);
myConfigureInterpretersPanel.add(new PyConfigureInterpretersLinkPanel(myPanel), BorderLayout.CENTER);
myInterpreterList.setSdkCombo(mySdkCombo);
}
@Override
public JComponent createComponent() {
return myPanel;
}
@Override
public boolean isModified() {
final Sdk sdk = getSdk();
return sdk != myProjectSdksModel.findSdk((Sdk)mySdkCombo.getSelectedItem());
}
@Nullable
private Sdk getSdk() {
if (myModule == null) {
return ProjectRootManager.getInstance(myProject).getProjectSdk();
}
final ModuleRootManager rootManager = ModuleRootManager.getInstance(myModule);
return rootManager.getSdk();
}
@Override
public void apply() throws ConfigurationException {
final Sdk selectedSdk = myProjectSdksModel.findSdk((Sdk)mySdkCombo.getSelectedItem());
if (myModule == null) {
final ProjectRootManager rootManager = ProjectRootManager.getInstance(myProject);
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
rootManager.setProjectSdk(selectedSdk);
}
});
}
else {
ModuleRootModificationUtil.setModuleSdk(myModule, selectedSdk);
}
final Sdk prevSdk = ProjectRootManager.getInstance(myProject).getProjectSdk();
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
ProjectRootManager.getInstance(myProject).setProjectSdk(selectedSdk);
}
});
myProjectSdksModel.setProjectSdk(selectedSdk);
// update string literals if different LanguageLevel was selected
if (prevSdk != null && selectedSdk != null) {
final PythonSdkFlavor flavor1 = PythonSdkFlavor.getFlavor(selectedSdk);
final PythonSdkFlavor flavor2 = PythonSdkFlavor.getFlavor(prevSdk);
if (flavor1 != null && flavor2 != null) {
final LanguageLevel languageLevel1 = flavor1.getLanguageLevel(selectedSdk);
final LanguageLevel languageLevel2 = flavor2.getLanguageLevel(prevSdk);
if ((languageLevel1.isPy3K() && languageLevel2.isPy3K()) ||
(!languageLevel1.isPy3K()) && !languageLevel2.isPy3K()) {
return;
}
}
}
rehighlightStrings(myProject);
}
public static void rehighlightStrings(final @NotNull Project project) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
for (Editor editor : EditorFactory.getInstance().getAllEditors()) {
if (editor instanceof EditorEx && editor.getProject() == project) {
final VirtualFile vFile = ((EditorEx)editor).getVirtualFile();
if (vFile != null) {
final EditorHighlighter highlighter = EditorHighlighterFactory.getInstance().createEditorHighlighter(project, vFile);
((EditorEx)editor).setHighlighter(highlighter);
}
}
}
}
});
}
@Override
public void reset() {
updateSdkList(false);
final Sdk sdk = getSdk();
mySdkCombo.setSelectedItem(myProjectSdksModel.getProjectSdks().get(sdk));
}
private void updateSdkList(boolean preserveSelection) {
final List<Sdk> sdkList = myInterpreterList.getAllPythonSdks();
Sdk selection = preserveSelection ? (Sdk)mySdkCombo.getSelectedItem() : null;
if (!sdkList.contains(selection)) {
selection = null;
}
VirtualEnvProjectFilter.removeNotMatching(myProject, sdkList);
// if the selection is a non-matching virtualenv, show it anyway
if (selection != null && !sdkList.contains(selection)) {
sdkList.add(0, selection);
}
sdkList.add(0, null);
mySdkCombo.setRenderer(new PySdkListCellRenderer());
mySdkCombo.setModel(new CollectionComboBoxModel(sdkList, selection));
}
@Override
public void disposeUIResources() {
myProjectSdksModel.removeListener(myListener);
myInterpreterList.disposeModel();
}
private static class MyListener implements SdkModel.Listener {
private final PyActiveSdkConfigurable myConfigurable;
public MyListener(PyActiveSdkConfigurable configurable) {
myConfigurable = configurable;
}
@Override
public void sdkAdded(Sdk sdk) {
myConfigurable.reset();
}
@Override
public void beforeSdkRemove(Sdk sdk) {
myConfigurable.updateSdkList(true);
}
@Override
public void sdkChanged(Sdk sdk, String previousName) {
myConfigurable.updateSdkList(true);
}
@Override
public void sdkHomeSelected(Sdk sdk, String newSdkHome) {
}
}
}
@@ -0,0 +1,60 @@
package com.jetbrains.python.configuration;
import com.intellij.application.options.ModuleAwareProjectConfigurable;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.UnnamedConfigurable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.ModuleRootManager;
import com.jetbrains.python.sdk.PythonSdkUpdater;
import com.jetbrains.python.testing.VFSTestFrameworkListener;
import org.jetbrains.annotations.NotNull;
/**
* @author yole
*/
public class PyActiveSdkModuleConfigurable extends ModuleAwareProjectConfigurable implements Configurable.Composite {
private final Project myProject;
private final Configurable mySdkConfigurable;
public PyActiveSdkModuleConfigurable(Project project) {
super(project, "Project Interpreter", "reference.settings.project.interpreter");
myProject = project;
mySdkConfigurable = new PythonSdkConfigurable(project);
}
@NotNull
@Override
protected UnnamedConfigurable createModuleConfigurable(Module module) {
return new PyActiveSdkConfigurable(module);
}
@Override
protected UnnamedConfigurable createDefaultProjectConfigurable() {
return new PyActiveSdkConfigurable(myProject);
}
@Override
public void apply() throws ConfigurationException {
super.apply();
// TODO[catherine] proper per-module caching of framework installed state
for (Module module : ModuleManager.getInstance(myProject).getModules()) {
final Sdk sdk = ModuleRootManager.getInstance(module).getSdk();
if (sdk != null) {
VFSTestFrameworkListener.getInstance().updateAllTestFrameworks(sdk);
break;
}
}
PythonSdkUpdater.getInstance().updateActiveSdks(myProject, 0);
}
@Override
public Configurable[] getConfigurables() {
return new Configurable[] { mySdkConfigurable };
}
}
@@ -0,0 +1,68 @@
package com.jetbrains.python.configuration;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel;
import com.intellij.openapi.util.Comparing;
import com.jetbrains.python.sdk.PythonSdkType;
import javax.swing.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* Manages the SDK model shared between PythonSdkConfigurable and PyActiveSdkConfigurable.
*
* @author yole
*/
public class PyConfigurableInterpreterList {
private ProjectSdksModel myModel;
private JComboBox mySdkCombo;
public void setSdkCombo(final JComboBox sdkCombo) {
mySdkCombo = sdkCombo;
}
public void setSelectedSdk(final Sdk selectedSdk) {
if (mySdkCombo != null)
mySdkCombo.setSelectedItem(selectedSdk);
}
public static PyConfigurableInterpreterList getInstance(Project project) {
return ServiceManager.getService(project, PyConfigurableInterpreterList.class);
}
public ProjectSdksModel getModel() {
if (myModel == null) {
myModel = new ProjectSdksModel();
myModel.reset(null);
}
return myModel;
}
public void disposeModel() {
if (myModel != null) {
myModel.disposeUIResources();
myModel = null;
}
}
public List<Sdk> getAllPythonSdks() {
List<Sdk> result = new ArrayList<Sdk>();
for (Sdk sdk : getModel().getSdks()) {
if (sdk.getSdkType() instanceof PythonSdkType) {
result.add(sdk);
}
}
Collections.sort(result, new Comparator<Sdk>() {
@Override
public int compare(Sdk o1, Sdk o2) {
return Comparing.compare(o1.getName(), o2.getName());
}
});
return result;
}
}
@@ -0,0 +1,41 @@
package com.jetbrains.python.configuration;
import com.intellij.ide.DataManager;
import com.intellij.openapi.options.newEditor.OptionsEditor;
import com.intellij.ui.ClickListener;
import com.intellij.ui.components.JBLabel;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
/**
* @author traff
*/
public class PyConfigureInterpretersLinkPanel extends JPanel {
private final JBLabel myConfigureLabel;
public PyConfigureInterpretersLinkPanel(final JPanel parentPanel) {
super(new BorderLayout());
myConfigureLabel = new JBLabel("<html><a href=\"#\">Configure Interpreters");
myConfigureLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
new ClickListener() {
@Override
public boolean onClick(MouseEvent e, int clickCount) {
if (clickCount == 1) {
final OptionsEditor optionsEditor = OptionsEditor.KEY.getData(DataManager.getInstance().getDataContext(parentPanel));
if (optionsEditor != null) {
PythonSdkConfigurable configurable = optionsEditor.findConfigurable(PythonSdkConfigurable.class);
if (configurable != null) {
optionsEditor.clearSearchAndSelect(configurable);
}
return true;
}
}
return false;
}
}.installOn(myConfigureLabel);
add(myConfigureLabel, BorderLayout.CENTER);
}
}
@@ -0,0 +1,32 @@
package com.jetbrains.python.configuration;
import com.intellij.application.options.ModuleAwareProjectConfigurable;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.options.OptionalConfigurable;
import com.intellij.openapi.options.UnnamedConfigurable;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
/**
* @author yole
*/
public class PyDependenciesConfigurable extends ModuleAwareProjectConfigurable implements OptionalConfigurable {
private final Project myProject;
public PyDependenciesConfigurable(Project project) {
super(project, "Project Dependencies", "reference.settingsdialog.project.dependencies");
myProject = project;
}
@NotNull
@Override
protected UnnamedConfigurable createModuleConfigurable(Module module) {
return new PyModuleDependenciesConfigurable(module);
}
@Override
public boolean needDisplay() {
return ModuleManager.getInstance(myProject).getModules().length > 1;
}
}
@@ -0,0 +1,59 @@
package com.jetbrains.python.configuration;
import com.intellij.openapi.diff.DiffContent;
import com.intellij.openapi.diff.SimpleContent;
import com.intellij.openapi.diff.impl.settings.DiffPreviewProvider;
import com.jetbrains.python.PythonFileType;
import org.jetbrains.annotations.NonNls;
/**
* @author oleg
*/
public class PyDiffPreviewProvider extends DiffPreviewProvider {
@Override
public DiffContent[] createContents() {
return new DiffContent[]{createContent(LEFT_TEXT), createContent(CENTER_TEXT), createContent(RIGHT_TEXT)};
}
private static SimpleContent createContent(final String text) {
return new SimpleContent(text, PythonFileType.INSTANCE);
}
@NonNls private static final String LEFT_TEXT = "class MyClass\n" +
" value = 123\n" +
"\n" +
" def left_only(self):\n" +
" bar(123)\n" +
"\n" +
" def bar(self, a)\n" +
" print a\n"+
"\n"+
" def foo(self):\n" +
" pass # Left changes\n"+
"\n"+
"\n";
@NonNls private static final String CENTER_TEXT = "class MyClass\n" +
" value = 123\n" +
"\n" +
" def bar(self, a)\n" +
" print a\n"+
"\n"+
" def foo(self):\n" +
" pass\n" +
"\n" +
"\n" +
" def removed_from_left(self):\n" +
" bar('PyCharmRulezzz')";
@NonNls private static final String RIGHT_TEXT = "class MyClass\n" +
" value = -123\n" +
"\n" +
" def bar(self, a)\n" +
" print a\n"+
"\n"+
" def foo(self):\n" +
" pass # Right changes\n" +
"\n" +
"\n" +
" def removed_from_left(self):\n" +
" bar('PyCharmRulezzz')";
}
@@ -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.jetbrains.python.configuration.PyModuleDependenciesConfigurable">
<grid id="27dc6" binding="myMainPanel" 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="20" y="20" width="500" height="400"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<component id="d3225" 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 value="Project depends on these projects:"/>
</properties>
</component>
<grid id="4caac" binding="myListHolderPanel" layout-manager="BorderLayout" hgap="0" vgap="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/>
</grid>
</children>
</grid>
</form>
@@ -0,0 +1,118 @@
package com.jetbrains.python.configuration;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.UnnamedConfigurable;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.ModuleOrderEntry;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.OrderEntry;
import com.intellij.ui.CheckBoxList;
import com.intellij.ui.ToolbarDecorator;
import com.intellij.util.Function;
import com.intellij.util.ui.EditableListModelDecorator;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @author yole
*/
public class PyModuleDependenciesConfigurable implements UnnamedConfigurable {
private final Module myModule;
private List<Module> myInitialDependencies;
private JPanel myMainPanel;
private JPanel myListHolderPanel;
private CheckBoxList<Module> myDependenciesList;
public PyModuleDependenciesConfigurable(Module module) {
myModule = module;
myDependenciesList = new CheckBoxList<Module>();
resetModel();
ToolbarDecorator decorator = ToolbarDecorator.createDecorator(myDependenciesList,
new EditableListModelDecorator((DefaultListModel) myDependenciesList.getModel()));
decorator.disableRemoveAction();
myListHolderPanel.add(decorator.createPanel(), BorderLayout.CENTER);
}
private void resetModel() {
List<Module> possibleDependencies = new ArrayList<Module>();
myInitialDependencies = Arrays.asList(ModuleRootManager.getInstance(myModule).getDependencies());
possibleDependencies.addAll(myInitialDependencies);
for (Module otherModule : ModuleManager.getInstance(myModule.getProject()).getModules()) {
if (!possibleDependencies.contains(otherModule) && otherModule != myModule) {
possibleDependencies.add(otherModule);
}
}
myDependenciesList.setItems(possibleDependencies, new Function<Module, String>() {
@Override
public String fun(Module module) {
return module.getName();
}
});
myDependenciesList.setBorder(null);
for (Module dependency : myInitialDependencies) {
myDependenciesList.setItemSelected(dependency, true);
}
}
@Nullable
@Override
public JComponent createComponent() {
return myMainPanel;
}
@Override
public boolean isModified() {
return collectDependencies().equals(myInitialDependencies);
}
private List<Module> collectDependencies() {
List<Module> result = new ArrayList<Module>();
for (int i = 0; i < myDependenciesList.getItemsCount(); i++) {
Module module = (Module)myDependenciesList.getItemAt(i);
if (myDependenciesList.isItemSelected(module)) {
result.add(module);
}
}
return result;
}
@Override
public void apply() throws ConfigurationException {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
ModifiableRootModel model = ModuleRootManager.getInstance(myModule).getModifiableModel();
List<ModuleOrderEntry> entries = new ArrayList<ModuleOrderEntry>();
for (OrderEntry entry : model.getOrderEntries()) {
if (entry instanceof ModuleOrderEntry) {
entries.add((ModuleOrderEntry) entry);
}
}
for (ModuleOrderEntry entry : entries) {
model.removeOrderEntry(entry);
}
for (Module module : collectDependencies()) {
model.addModuleOrderEntry(module);
}
model.commit();
}
});
}
@Override
public void reset() {
resetModel();
}
@Override
public void disposeUIResources() {
}
}
@@ -0,0 +1,42 @@
package com.jetbrains.python.configuration;
import com.intellij.application.options.ModuleAwareProjectConfigurable;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.NonDefaultProjectConfigurable;
import com.intellij.openapi.options.OptionalConfigurable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ui.configuration.PlatformContentEntriesConfigurable;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.model.java.JavaSourceRootType;
/**
* @author yole
*/
public class PythonContentEntriesConfigurable extends ModuleAwareProjectConfigurable implements NonDefaultProjectConfigurable, OptionalConfigurable {
private final Project myProject;
public PythonContentEntriesConfigurable(final Project project) {
super(project, "Project Structure", "reference.settingsdialog.project.structure");
myProject = project;
}
@Nullable
private static Module getSingleModule(Project project) {
return ArrayUtil.getFirstElement(ModuleManager.getInstance(project).getModules());
}
@Override
public boolean needDisplay() {
return getSingleModule(myProject) != null;
}
@NotNull
@Override
protected Configurable createModuleConfigurable(Module module) {
return new PlatformContentEntriesConfigurable(module, JavaSourceRootType.SOURCE);
}
}
@@ -0,0 +1,316 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR 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.configuration;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileTypes.FileTypes;
import com.intellij.openapi.projectRoots.SdkAdditionalData;
import com.intellij.openapi.projectRoots.SdkModificator;
import com.intellij.openapi.projectRoots.ui.SdkPathEditor;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.AnActionButton;
import com.intellij.ui.ListCellRendererWrapper;
import com.intellij.ui.ListUtil;
import com.intellij.ui.ToolbarDecorator;
import com.intellij.ui.components.JBList;
import com.intellij.util.ArrayUtil;
import com.jetbrains.python.sdk.PythonSdkAdditionalData;
import com.jetbrains.python.sdk.PythonSdkType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.util.List;
import java.util.Set;
/**
* @author traff
*/
public class PythonPathEditor extends SdkPathEditor {
private final PathListModel myPathListModel;
public PythonPathEditor(final String displayName,
final OrderRootType orderRootType,
final FileChooserDescriptor descriptor) {
super(displayName, orderRootType, descriptor);
myPathListModel = new PathListModel(orderRootType, getListModel());
}
public void reset(@Nullable SdkModificator modificator) {
if (modificator != null) {
List<VirtualFile> list = Lists.newArrayList(modificator.getRoots(getOrderRootType()));
resetPath(myPathListModel.reset(list, modificator));
}
else {
setEnabled(false);
}
}
public void reload(@Nullable SdkModificator sdkModificator) {
if (sdkModificator != null) {
List<VirtualFile> list = Lists.newArrayList(sdkModificator.getRoots(getOrderRootType()));
resetPath(myPathListModel.reload(list));
setModified(true);
}
else {
setEnabled(false);
}
}
@Override
public void apply(SdkModificator sdkModificator) {
sdkModificator.removeRoots(getOrderRootType());
// add all items
for (int i = 0; i < myPathListModel.getRowCount(); i++) {
VirtualFile path = myPathListModel.getValueAt(i);
if (!myPathListModel.isExcluded(path)) {
sdkModificator.addRoot(path, getOrderRootType());
}
}
setModified(false);
myPathListModel.apply(sdkModificator);
}
@Override
protected VirtualFile[] adjustAddedFileSet(Component component, VirtualFile[] files) {
for (int i = 0, filesLength = files.length; i < filesLength; i++) {
if (files[i].getFileType() == FileTypes.ARCHIVE) {
files[i] = JarFileSystem.getInstance().getJarRootForLocalFile(files[i]);
}
}
if (myPathListModel.add(Lists.newArrayList(files))) {
setModified(true);
}
return files;
}
@Override
protected void doRemoveItems(int[] idxs, JList list) {
List<Pair<VirtualFile, Integer>> removed = Lists.newArrayList();
for (int i : idxs) {
removed.add(Pair.create((VirtualFile)getListModel().get(i), i));
}
ListUtil.removeIndices(list, myPathListModel.remove(removed));
list.updateUI();
setModified(true);
}
@Override
protected ListCellRenderer createListCellRenderer(JBList list) {
return new PythonPathListCellRenderer(super.createListCellRenderer(list), myPathListModel);
}
@Override
protected void addToolbarButtons(ToolbarDecorator toolbarDecorator) {
AnActionButton reloadButton = new AnActionButton("Reload List of Paths", AllIcons.Actions.Refresh) {
@Override
public void actionPerformed(AnActionEvent e) {
onReloadButtonClicked();
}
};
toolbarDecorator.addExtraAction(reloadButton);
}
protected void onReloadButtonClicked() {
}
private static class PathListModel {
private Set<VirtualFile> myAdded = Sets.newHashSet();
private Set<VirtualFile> myExcluded = Sets.newHashSet();
private Set<VirtualFile> myFoundFiles = Sets.newHashSet();
private List<VirtualFile> myFilteredOut = Lists.newArrayList();
private final DefaultListModel myListModel;
private final OrderRootType myOrderRootType;
private Set<VirtualFile> myUserAddedToRemove = Sets.newHashSet();
public PathListModel(OrderRootType orderRootType, DefaultListModel listModel) {
myOrderRootType = orderRootType;
myListModel = listModel;
}
private int getRowCount() {
return myListModel.getSize();
}
private VirtualFile getValueAt(int row) {
return (VirtualFile)myListModel.get(row);
}
public boolean add(List<VirtualFile> files) {
for (VirtualFile file : files) {
if (!myFoundFiles.contains(file)) {
if (!myExcluded.remove(file)) { //if it was excluded we only delete exclusion mark
myAdded.add(file);
myUserAddedToRemove.remove(file);
}
else {
myFoundFiles.add(file);
return true;
}
} else {
myExcluded.remove(file);
}
}
return false;
}
public int[] remove(List<Pair<VirtualFile, Integer>> files) {
List<Integer> toRemove = Lists.newArrayList();
for (Pair<VirtualFile, Integer> e : files) {
if (myAdded.contains(e.first)) {
toRemove.add(e.second);
myAdded.remove(e.first);
myUserAddedToRemove.add(e.first);
}
else if (myExcluded.contains(e.first)) {
myExcluded.remove(e.first);
}
else {
myExcluded.add(e.first);
}
}
return ArrayUtil.toIntArray(toRemove);
}
public void apply(SdkModificator sdkModificator) {
sdkModificator.setSdkAdditionalData(collectSdkAdditionalData(sdkModificator));
addFilteredOutRoots(sdkModificator);
}
private void addFilteredOutRoots(SdkModificator sdkModificator) {
for (VirtualFile file : myFilteredOut) {
sdkModificator.addRoot(file, myOrderRootType);
}
}
private SdkAdditionalData collectSdkAdditionalData(SdkModificator sdkModificator) {
PythonSdkAdditionalData data = (PythonSdkAdditionalData)sdkModificator.getSdkAdditionalData();
if (data == null) {
data = new PythonSdkAdditionalData(null);
}
data.setAddedPathsFromVirtualFiles(myAdded);
data.setExcludedPathsFromVirtualFiles(myExcluded);
return data;
}
public void setAdded(Set<VirtualFile> added) {
myAdded = Sets.newHashSet(added);
}
public void setExcluded(Set<VirtualFile> excluded) {
myExcluded = Sets.newHashSet(excluded);
}
public String getPresentationSuffix(VirtualFile file) {
if (myAdded.contains(file)) {
return "(added by user)";
}
if (myExcluded.contains(file)) {
return "(removed by user)";
}
return "";
}
public List<VirtualFile> reload(List<VirtualFile> list) {
myFoundFiles.clear();
myFoundFiles.addAll(list);
List<VirtualFile> result = filterOutStubs(list, myFilteredOut);
result.removeAll(myUserAddedToRemove);
result.addAll(myAdded);
return result;
}
public List<VirtualFile> reset(List<VirtualFile> list, SdkModificator modificator) {
myFilteredOut.clear();
List<VirtualFile> result = filterOutStubs(list, myFilteredOut);
myFoundFiles.clear();
myFoundFiles.addAll(list);
myUserAddedToRemove.clear();
if (modificator.getSdkAdditionalData() instanceof PythonSdkAdditionalData) {
PythonSdkAdditionalData data = (PythonSdkAdditionalData)modificator.getSdkAdditionalData();
setAdded(data.getAddedPathFiles());
setExcluded(data.getExcludedPathFiles());
result.addAll(myExcluded);
}
else if (modificator.getSdkAdditionalData() == null) {
myAdded.clear();
myExcluded.clear();
}
return result;
}
private static List<VirtualFile> filterOutStubs(List<VirtualFile> list, List<VirtualFile> filteredOut) {
List<VirtualFile> result = Lists.newArrayList();
filteredOut.clear();
for (VirtualFile file : list) {
if (!isStubPath(file)) {
result.add(file);
}
else {
filteredOut.add(file);
}
}
return result;
}
private static boolean isStubPath(@NotNull VirtualFile file) {
final String path = PythonSdkType.getSkeletonsRootPath(PathManager.getSystemPath());
final VirtualFile skeletonRoot = LocalFileSystem.getInstance().findFileByPath(path);
if (skeletonRoot != null) {
return file.getPath().startsWith(skeletonRoot.getPath());
}
else {
return false;
}
}
public boolean isExcluded(VirtualFile path) {
return myExcluded.contains(path);
}
}
private static class PythonPathListCellRenderer extends ListCellRendererWrapper<VirtualFile> {
private final PathListModel model;
public PythonPathListCellRenderer(final ListCellRenderer listCellRenderer, PathListModel model) {
super();
this.model = model;
}
@Override
public void customize(JList list, VirtualFile value, int index, boolean selected, boolean hasFocus) {
String suffix = model.getPresentationSuffix(value);
if (suffix.length() > 0) {
suffix = " " + suffix;
}
setText(value != null ? value.getPresentableUrl() + suffix : "");
}
}
}
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.jetbrains.python.configuration.PythonSdkConfigurable">
<grid id="27dc6" binding="myPanel" 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>
<xy x="20" y="20" width="611" height="400"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<grid id="feff7" binding="mySplitterHolder" layout-manager="BorderLayout" hgap="0" vgap="0">
<constraints>
<grid row="0" column="0" row-span="1" col-span="2" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<grid id="6feb9" binding="myNotificationsPlaceholder" layout-manager="BorderLayout" hgap="0" vgap="0">
<constraints border-constraint="South"/>
<properties>
<background swing-color="ArrowButton.background"/>
<minimumSize width="6" height="6"/>
<preferredSize width="6" height="23"/>
</properties>
<border type="none"/>
<children/>
</grid>
</children>
</grid>
</children>
</grid>
</form>
@@ -0,0 +1,571 @@
package com.jetbrains.python.configuration;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.intellij.CommonBundle;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.*;
import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl;
import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.Splitter;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.remotesdk.RemoteCredentials;
import com.intellij.ui.*;
import com.intellij.ui.components.JBList;
import com.intellij.ui.components.JBTabbedPane;
import com.intellij.util.Consumer;
import com.intellij.util.NullableConsumer;
import com.intellij.util.NullableFunction;
import com.intellij.util.containers.FactoryMap;
import com.intellij.webcore.packaging.PackagesNotificationPanel;
import com.jetbrains.python.packaging.ui.PyInstalledPackagesPanel;
import com.jetbrains.python.packaging.ui.PyPackageManagementService;
import com.jetbrains.python.remote.PythonRemoteInterpreterManager;
import com.jetbrains.python.sdk.*;
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
import icons.PythonIcons;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.*;
import java.util.*;
import java.util.List;
public class PythonSdkConfigurable implements Configurable, Configurable.NoScroll {
private JPanel myPanel;
private JList mySdkList;
private JPanel mySplitterHolder;
private PackagesNotificationPanel myNotificationsArea;
private JPanel myNotificationsPlaceholder;
private PythonPathEditor myPathEditor;
private boolean mySdkListChanged = false;
private final PyConfigurableInterpreterList myInterpreterList;
private final ProjectSdksModel myProjectSdksModel;
private final PyInstalledPackagesPanel myPackagesPanel;
private Map<Sdk, SdkModificator> myModificators = new FactoryMap<Sdk, SdkModificator>() {
@Override
protected SdkModificator create(Sdk sdk) {
return sdk.getSdkModificator();
}
};
private Set<SdkModificator> myModifiedModificators = new HashSet<SdkModificator>();
private Sdk myPreviousSelection;
private boolean myFirstReset;
private final Project myProject;
private boolean myNewProject = false;
private boolean myShowOtherProjectVirtualenvs = false;
public void setNewProject(final boolean newProject) {
myNewProject = newProject;
}
public PythonSdkConfigurable(Project project) {
myProject = project;
myInterpreterList = PyConfigurableInterpreterList.getInstance(myProject);
myProjectSdksModel = myInterpreterList.getModel();
myFirstReset = true;
mySdkList = new JBList();
mySdkList.setCellRenderer(new PySdkListCellRenderer("", myModificators));
mySdkList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
ToolbarDecorator decorator = ToolbarDecorator.createDecorator(mySdkList).disableUpDownActions()
.setAddAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton button) {
addSdk(button);
}
})
.setEditAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton button) {
editSdk();
}
})
.setRemoveAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton button) {
removeSdk();
}
})
.addExtraAction(new CreateVirtualEnvButton())
.addExtraAction(new ToggleVirtualEnvFilterButton());
final Splitter splitter = new Splitter(true);
/*
final JScrollPane sdkListPane = ScrollPaneFactory.createScrollPane(mySdkList,
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
sdkListPane.setPreferredSize(new Dimension(10, 10));
*/
splitter.setFirstComponent(decorator.createPanel());
myPathEditor =
new PythonPathEditor("Classes", OrderRootType.CLASSES, FileChooserDescriptorFactory.createAllButJarContentsDescriptor()) {
@Override
protected void onReloadButtonClicked() {
reloadSdk();
}
};
myNotificationsArea = new PackagesNotificationPanel(project);
myNotificationsPlaceholder.add(myNotificationsArea.getComponent(), BorderLayout.CENTER);
final JBTabbedPane tabbedPane = new JBTabbedPane(SwingConstants.TOP);
myPackagesPanel = new PyInstalledPackagesPanel(project, myNotificationsArea);
tabbedPane.addTab("Packages", myPackagesPanel);
JPanel panel1 = new JPanel(new GridBagLayout());
Insets anInsets1 = new Insets(2, 2, 2, 2);
JScrollPane scrollPane1 = ScrollPaneFactory.createScrollPane(myPathEditor.createComponent(),
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane1.setPreferredSize(new Dimension(500, 500));
panel1.add(scrollPane1, new GridBagConstraints(0, 0, 1, 8, 1.0, 1.0,
GridBagConstraints.CENTER,
GridBagConstraints.BOTH,
anInsets1, 0, 0));
tabbedPane.addTab("Paths", panel1);
splitter.setSecondComponent(tabbedPane);
mySplitterHolder.add(splitter, BorderLayout.CENTER);
addListeners();
}
private void addListeners() {
myProjectSdksModel.addListener(new SdkModel.Listener() {
@Override
public void sdkAdded(Sdk sdk) {
}
@Override
public void beforeSdkRemove(Sdk sdk) {
}
@Override
public void sdkChanged(Sdk sdk, String previousName) {
refreshSdkList();
}
@Override
public void sdkHomeSelected(Sdk sdk, String newSdkHome) {
}
});
myPackagesPanel.addPathChangedListener(new Consumer<Sdk>() {
@Override
public void consume(Sdk sdk) {
updateSdkPaths(sdk);
}
});
myNotificationsArea.addLinkHandler(PyInstalledPackagesPanel.CREATE_VENV, new Runnable() {
@Override
public void run() {
createVirtualEnv(getSelectedSdk());
}
});
mySdkList.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent event) {
updateUI(getSelectedSdk());
}
});
}
private void updateUI(final Sdk selectedSdk) {
if (myPreviousSelection != null) {
saveSdkPaths(myPreviousSelection);
}
myProjectSdksModel.setProjectSdk(selectedSdk);
updateSdkPaths(selectedSdk);
myPreviousSelection = selectedSdk;
myPackagesPanel.updatePackages(selectedSdk == null ? null : new PyPackageManagementService(myProject, selectedSdk));
if (selectedSdk != null) {
myPackagesPanel.updateNotifications(selectedSdk);
}
}
private void createVirtualEnv(Sdk sdk) {
CreateVirtualEnvDialog.VirtualEnvCallback callback = new CreateVirtualEnvDialog.VirtualEnvCallback() {
@Override
public void virtualEnvCreated(Sdk sdk, boolean associateWithProject, boolean setAsProjectInterpreter) {
PythonSdkType.setupSdkPaths(sdk, myProject, null);
if (associateWithProject) {
SdkAdditionalData additionalData = sdk.getSdkAdditionalData();
if (additionalData == null) {
additionalData = new PythonSdkAdditionalData(PythonSdkFlavor.getFlavor(sdk.getHomePath()));
((ProjectJdkImpl)sdk).setSdkAdditionalData(additionalData);
}
if (myNewProject) {
((PythonSdkAdditionalData)additionalData).associateWithNewProject();
}
else {
((PythonSdkAdditionalData)additionalData).associateWithProject(myProject);
}
}
addCreatedSdk(sdk, true, setAsProjectInterpreter);
}
};
final List<Sdk> allSdks = PyConfigurableInterpreterList.getInstance(myProject).getAllPythonSdks();
final CreateVirtualEnvDialog dialog = new CreateVirtualEnvDialog(myProject, myNewProject, allSdks, sdk);
dialog.show();
if (dialog.isOK()) {
dialog.createVirtualEnv(allSdks, callback);
}
}
public String getDisplayName() {
return "Python Interpreters";
}
public String getHelpTopic() {
return "python_interpreter";
}
public JComponent createComponent() {
return myPanel;
}
public boolean isModified() {
return mySdkListChanged ||
myProjectSdksModel.isModified() ||
myPathEditor.isModified() ||
!myModifiedModificators.isEmpty();
}
@Nullable
private String getSelectedSdkName() {
final Sdk selectedSdk = (Sdk)mySdkList.getSelectedValue();
return selectedSdk == null ? null : selectedSdk.getName();
}
public void apply() throws ConfigurationException {
if (myPreviousSelection != null) {
saveSdkPaths(myPreviousSelection);
}
for (SdkModificator modificator : myModifiedModificators) {
modificator.commitChanges();
}
myModificators.clear();
myModifiedModificators.clear();
myProjectSdksModel.apply();
mySdkListChanged = false;
}
/**
* Returns the stable copy of the SDK currently selected in the SDK table.
*
* @return the selected SDK, or null if there's no selection
*/
@Nullable
public Sdk getRealSelectedSdk() {
return ProjectJdkTable.getInstance().findJdk(getSelectedSdkName());
}
@Nullable
public Sdk getSelectedSdk() {
return (Sdk)mySdkList.getSelectedValue();
}
public void reset() {
clearModificators();
if (myFirstReset) {
myFirstReset = false;
}
else {
myProjectSdksModel.reset(null);
}
refreshSdkList();
final Sdk selectedSdk = getRealSelectedSdk();
if (selectedSdk != null) {
myPackagesPanel.updateNotifications(selectedSdk);
}
}
private void clearModificators() {
myModificators.clear();
myModifiedModificators.clear();
myPreviousSelection = null;
}
private void refreshSdkList() {
final List<Sdk> pythonSdks = myInterpreterList.getAllPythonSdks();
Sdk projectSdk = myProjectSdksModel.getProjectSdk();
if (!myShowOtherProjectVirtualenvs) {
VirtualEnvProjectFilter.removeNotMatching(myProject, pythonSdks);
}
Collections.sort(pythonSdks, new PreferredSdkComparator());
mySdkList.setModel(new CollectionListModel<Sdk>(pythonSdks));
mySdkListChanged = false;
if (projectSdk == null) projectSdk = getSdk();
if (projectSdk != null) {
projectSdk = myProjectSdksModel.findSdk(projectSdk.getName());
mySdkList.clearSelection();
mySdkList.setSelectedValue(projectSdk, true);
mySdkList.updateUI();
}
}
@Nullable
private Sdk getSdk() {
final Module[] modules = ModuleManager.getInstance(myProject).getModules();
if (modules.length > 0) {
final Module module = modules[0];
final ModuleRootManager rootManager = ModuleRootManager.getInstance(module);
return rootManager.getSdk();
}
return ProjectRootManager.getInstance(myProject).getProjectSdk();
}
private void addSdk(AnActionButton button) {
InterpreterPathChooser
.show(myProject, myProjectSdksModel.getSdks(), button.getPreferredPopupPoint(), false, new NullableConsumer<Sdk>() {
@Override
public void consume(Sdk sdk) {
addCreatedSdk(sdk, false, false);
}
});
}
private void addCreatedSdk(@Nullable final Sdk sdk, boolean newVirtualEnv, boolean makeActive) {
if (sdk != null) {
boolean isVirtualEnv = PythonSdkType.isVirtualEnv(sdk);
boolean askSetAsProjectInterpreter = !myProject.isDefault() && !myNewProject;
if (askSetAsProjectInterpreter && isVirtualEnv && !newVirtualEnv) {
AddVEnvOptionsDialog dialog = new AddVEnvOptionsDialog(myPanel);
dialog.show();
if (dialog.getExitCode() != DialogWrapper.OK_EXIT_CODE) {
return;
}
SdkModificator modificator = myModificators.get(sdk);
setSdkAssociated(modificator, !dialog.makeAvailableToAll());
myModifiedModificators.add(modificator);
makeActive = dialog.useForThisProject();
}
myProjectSdksModel.addSdk(sdk);
refreshSdkList();
mySdkList.setSelectedValue(sdk, true);
mySdkListChanged = true;
if (askSetAsProjectInterpreter && !isVirtualEnv && !PythonSdkType.isInvalid(sdk) && !PythonSdkType.isIncompleteRemote(sdk)) {
//TODO: make native mac dialog work
makeActive = Messages.showIdeaMessageDialog(myProject, "Do you want to set this interpreter as Project Interpreter?",
"Project Interpreter",
new String[]{CommonBundle.getYesButtonText(), CommonBundle.getNoButtonText()}, 0, null,
null
) == Messages.YES;
}
if (makeActive) {
SdkConfigurationUtil.setDirectoryProjectSdk(myProject, sdk);
myProjectSdksModel.setProjectSdk(sdk);
myInterpreterList.setSelectedSdk(sdk);
}
}
}
private void editSdk() {
final Sdk currentSdk = getSelectedSdk();
if (currentSdk != null) {
if (currentSdk.getSdkAdditionalData() instanceof RemoteCredentials) {
editRemoteSdk(currentSdk);
}
else {
editSdk(currentSdk);
}
updateUI(currentSdk);
}
}
private void editRemoteSdk(Sdk currentSdk) {
PythonRemoteInterpreterManager remoteInterpreterManager = PythonRemoteInterpreterManager.getInstance();
if (remoteInterpreterManager != null) {
final SdkModificator modificator = myModificators.get(currentSdk);
Set<Sdk> existingSdks = Sets.newHashSet(myProjectSdksModel.getSdks());
existingSdks.remove(currentSdk);
if (remoteInterpreterManager.editSdk(myProject, modificator, existingSdks)) {
myModifiedModificators.add(modificator);
}
}
}
private void editSdk(final Sdk currentSdk) {
final SdkModificator modificator = myModificators.get(currentSdk);
final EditSdkDialog dialog = new EditSdkDialog(myProject, modificator, new NullableFunction<String, String>() {
@Override
public String fun(String s) {
if (isDuplicateSdkName(s, currentSdk)) {
return "Please specify a unique name for the interpreter";
}
return null;
}
});
dialog.show();
if (dialog.isOK()) {
final boolean pathChanged = !Comparing.equal(currentSdk.getHomePath(), dialog.getHomePath());
if (!currentSdk.getName().equals(dialog.getName()) || pathChanged || dialog.isAssociateChanged()) {
myModifiedModificators.add(modificator);
modificator.setName(dialog.getName());
modificator.setHomePath(dialog.getHomePath());
if (dialog.isAssociateChanged()) {
setSdkAssociated(modificator, dialog.associateWithProject());
}
if (pathChanged) {
reloadSdk(currentSdk);
}
}
}
}
private void setSdkAssociated(SdkModificator modificator, boolean isAssociated) {
PythonSdkAdditionalData additionalData = (PythonSdkAdditionalData)modificator.getSdkAdditionalData();
if (additionalData == null) {
additionalData = new PythonSdkAdditionalData(PythonSdkFlavor.getFlavor(modificator.getHomePath()));
modificator.setSdkAdditionalData(additionalData);
}
if (isAssociated) {
additionalData.associateWithProject(myProject);
}
else {
additionalData.setAssociatedProjectPath(null);
}
}
private boolean isDuplicateSdkName(String s, Sdk sdk) {
for (Sdk existingSdk : myProjectSdksModel.getSdks()) {
if (existingSdk == sdk) {
continue;
}
String existingName;
if (myModificators.containsKey(existingSdk)) {
existingName = myModificators.get(existingSdk).getName();
}
else {
existingName = existingSdk.getName();
}
if (existingName.equals(s)) {
return true;
}
}
return false;
}
private void removeSdk() {
final Sdk current_sdk = getSelectedSdk();
if (current_sdk != null) {
myProjectSdksModel.removeSdk(current_sdk);
if (myModificators.containsKey(current_sdk)) {
SdkModificator modificator = myModificators.get(current_sdk);
myModifiedModificators.remove(modificator);
myModificators.remove(current_sdk);
}
refreshSdkList();
mySdkListChanged = true;
// TODO select initially selected SDK
if (mySdkList.getSelectedIndex() < 0) {
mySdkList.setSelectedIndex(0);
}
}
}
private void reloadSdk() {
final Sdk currentSdk = getSelectedSdk();
if (currentSdk != null) {
myModifiedModificators.add(myModificators.get(currentSdk));
reloadSdk(currentSdk);
}
}
private void reloadSdk(Sdk currentSdk) {
PythonSdkType.setupSdkPaths(myProject, null, currentSdk, myModificators.get(currentSdk)); // or must it be a RunWriteAction?
reloadSdkPaths(currentSdk);
}
public void disposeUIResources() {
myInterpreterList.disposeModel();
clearModificators();
myFirstReset = true;
}
private void saveSdkPaths(Sdk selection) {
SdkModificator modificator = myModificators.get(selection);
if (myPathEditor.isModified()) {
myPathEditor.apply(modificator);
myModifiedModificators.add(modificator);
}
}
private void reloadSdkPaths(Sdk selection) {
List<VirtualFile> rootPaths = Lists.newArrayList();
if (selection != null) {
Collections.addAll(rootPaths, selection.getRootProvider().getFiles(OrderRootType.CLASSES));
myPathEditor.reload(myModificators.get(selection));
}
else {
myPathEditor.reload(null);
}
}
private void updateSdkPaths(final Sdk selection) {
final List<VirtualFile> rootPaths = Lists.newArrayList();
if (selection != null) {
Collections.addAll(rootPaths, selection.getRootProvider().getFiles(OrderRootType.CLASSES));
myPathEditor.reset(myModificators.get(selection));
}
else {
myPathEditor.reset(null);
}
}
private class CreateVirtualEnvButton extends AnActionButton implements DumbAware {
public CreateVirtualEnvButton() {
super("Create Virtual Environment", PythonIcons.Python.Virtualenv);
}
@Override
public void actionPerformed(AnActionEvent e) {
Sdk selectedSdk = getSelectedSdk();
createVirtualEnv(selectedSdk);
}
}
private class ToggleVirtualEnvFilterButton extends ToggleActionButton implements DumbAware {
public ToggleVirtualEnvFilterButton() {
super("Show virtual environments associated with other projects", AllIcons.General.Filter);
}
@Override
public boolean isSelected(AnActionEvent e) {
return myShowOtherProjectVirtualenvs;
}
@Override
public void setSelected(AnActionEvent e, boolean state) {
myShowOtherProjectVirtualenvs = state;
refreshSdkList();
}
}
}
@@ -0,0 +1,50 @@
package com.jetbrains.python.configuration;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.util.io.FileUtil;
import com.jetbrains.python.sdk.PythonSdkAdditionalData;
import com.jetbrains.python.sdk.PythonSdkType;
import org.jetbrains.annotations.Nullable;
import java.util.List;
/**
* @author yole
*/
public class VirtualEnvProjectFilter implements Predicate<Sdk> {
private final String myBasePath;
public VirtualEnvProjectFilter(@Nullable final String basePath) {
myBasePath = basePath;
}
@Override
public boolean apply(@Nullable final Sdk input) {
if (input != null && PythonSdkType.isVirtualEnv(input)) {
PythonSdkAdditionalData data = (PythonSdkAdditionalData) input.getSdkAdditionalData();
if (data != null) {
final String path = data.getAssociatedProjectPath();
if (path != null && (myBasePath == null || !path.equals(myBasePath))) {
return true;
}
}
}
return false;
}
public static void removeNotMatching(Project project, List<Sdk> sdks) {
if (project != null) {
final String basePath = project.getBasePath();
if (basePath != null) {
Iterables.removeIf(sdks, new VirtualEnvProjectFilter(FileUtil.toSystemIndependentName(basePath)));
}
}
}
public static void removeAllAssociated(List<Sdk> sdks) {
Iterables.removeIf(sdks, new VirtualEnvProjectFilter(null));
}
}
@@ -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.jetbrains.python.newProject;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.SdkAdditionalData;
import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.platform.DirectoryProjectGenerator;
import com.intellij.platform.NewDirectoryProjectAction;
import com.jetbrains.python.sdk.PythonSdkAdditionalData;
import com.jetbrains.python.sdk.PythonSdkType;
import java.util.List;
/**
* User : catherine
*/
public class PythonNewDirectoryProjectAction extends NewDirectoryProjectAction {
private Sdk mySdk;
private boolean myInstallFramework;
public void actionPerformed(final AnActionEvent e) {
Project project = e.getData(PlatformDataKeys.PROJECT);
if (project == null) {
project = ProjectManager.getInstance().getDefaultProject();
}
PythonNewDirectoryProjectDialog dlg = new PythonNewDirectoryProjectDialog(project);
dlg.show();
if (dlg.getExitCode() != DialogWrapper.OK_EXIT_CODE) return;
mySdk = dlg.getSdk();
myInstallFramework = dlg.installFramework();
Project newProject = generateProject(project, dlg);
if (newProject != null) {
SdkConfigurationUtil.setDirectoryProjectSdk(newProject, mySdk);
final List<Sdk> sdks = PythonSdkType.getAllSdks();
for (Sdk sdk : sdks) {
final SdkAdditionalData additionalData = sdk.getSdkAdditionalData();
if (additionalData instanceof PythonSdkAdditionalData) {
((PythonSdkAdditionalData) additionalData).reassociateWithCreatedProject(newProject);
}
}
}
}
@Override
protected Object showSettings(DirectoryProjectGenerator generator, VirtualFile baseDir)
throws ProcessCanceledException {
Object settings = super.showSettings(generator, baseDir);
if (settings instanceof PyNewProjectSettings) {
((PyNewProjectSettings)settings).setSdk(mySdk);
((PyNewProjectSettings)settings).setInstallFramework(myInstallFramework);
}
return settings;
}
}
@@ -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.jetbrains.python.newProject;
import com.intellij.facet.ui.ValidationResult;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.platform.DirectoryProjectGenerator;
import com.intellij.platform.NewDirectoryProjectDialog;
import com.intellij.remotesdk.RemoteSdkData;
import com.intellij.ui.ComboboxWithBrowseButton;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.ui.components.JBLabel;
import com.jetbrains.python.PythonSdkChooserCombo;
import com.jetbrains.python.configuration.VirtualEnvProjectFilter;
import com.jetbrains.python.packaging.PyExternalProcessException;
import com.jetbrains.python.packaging.PyPackage;
import com.jetbrains.python.packaging.PyPackageManager;
import com.jetbrains.python.packaging.PyPackageManagerImpl;
import com.jetbrains.python.remote.PythonRemoteInterpreterManager;
import com.jetbrains.python.remote.RemoteProjectSettings;
import com.jetbrains.python.sdk.PreferredSdkComparator;
import com.jetbrains.python.sdk.PythonSdkType;
import com.jetbrains.python.sdk.flavors.JythonSdkFlavor;
import com.jetbrains.python.sdk.flavors.PyPySdkFlavor;
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Collections;
import java.util.List;
/**
* User : catherine
*/
public class PythonNewDirectoryProjectDialog extends NewDirectoryProjectDialog {
private ComboboxWithBrowseButton mySdkCombo;
private final JCheckBox myFrameworkCheckbox;
private boolean myInstallFrameworkChanged;
private final Project myProject;
protected PythonNewDirectoryProjectDialog(Project project) {
super(project);
myProject = project;
final List<Sdk> sdks = PythonSdkType.getAllSdks();
VirtualEnvProjectFilter.removeAllAssociated(sdks);
Collections.sort(sdks, PreferredSdkComparator.INSTANCE);
final Sdk preferred = sdks.isEmpty() ? null : sdks.iterator().next();
mySdkCombo = new PythonSdkChooserCombo(project, sdks, new Condition<Sdk>() {
@Override
public boolean value(Sdk sdk) {
return sdk == preferred;
}
});
final JLabel label = new JBLabel("Interpreter:", SwingConstants.LEFT) {
@Override
public Dimension getMinimumSize() {
return new JLabel("Project name:").getPreferredSize();
}
@Override
public Dimension getPreferredSize() {
return getMinimumSize();
}
};
label.setLabelFor(mySdkCombo);
final JPanel placeholder = getPlaceHolder();
final GridBagConstraints constraints = new GridBagConstraints();
constraints.gridx = 0;
constraints.gridy = 0;
constraints.anchor = GridBagConstraints.WEST;
constraints.insets = new Insets(0, 0, 0, 10);
placeholder.add(label, constraints);
constraints.gridx = 1;
constraints.gridy = 0;
constraints.fill = GridBagConstraints.BOTH;
constraints.weightx = 1.0;
constraints.insets = new Insets(0, 0, 0, 0);
placeholder.add(mySdkCombo, constraints);
final ActionListener listener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
checkValid();
}
};
myFrameworkCheckbox = new JBCheckBox("Install <framework>");
constraints.gridx = 0;
constraints.gridy = 1;
constraints.gridwidth = 2;
constraints.weightx = 0.0;
placeholder.add(myFrameworkCheckbox, constraints);
myFrameworkCheckbox.setVisible(false);
myFrameworkCheckbox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
myInstallFrameworkChanged = true;
checkValid();
}
});
mySdkCombo.addActionListener(listener);
mySdkCombo.getComboBox().addActionListener(listener);
myProjectTypeComboBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
selectCompatiblePython();
checkValid();
}
});
mySdkCombo.getComboBox().addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent event) {
checkValid();
}
});
final Dimension checkBoxSize = myFrameworkCheckbox.getPreferredSize();
myRootPane.setPreferredSize(new Dimension(myRootPane.getPreferredSize().width,
myRootPane.getPreferredSize().height + checkBoxSize.height));
checkValid();
}
@Override
protected Object getEmptyProjectGenerator() {
return new DirectoryProjectGenerator() {
@NotNull
@Nls
@Override
public String getName() {
return "Empty project";
}
@Nullable
@Override
public Object showGenerationSettings(VirtualFile baseDir) throws ProcessCanceledException {
if (PythonSdkType.isRemote(getSdk())) {
PythonRemoteInterpreterManager manager = PythonRemoteInterpreterManager.getInstance();
assert manager != null;
return manager.showRemoteProjectSettingsDialog(baseDir, (RemoteSdkData)getSdk().getSdkAdditionalData());
}
else {
return null;
}
}
@Override
public void generateProject(@NotNull Project project,
@NotNull VirtualFile baseDir,
Object settings,
@NotNull Module module) {
if (settings instanceof RemoteProjectSettings) {
PythonRemoteInterpreterManager manager = PythonRemoteInterpreterManager.getInstance();
assert manager != null;
manager.createDeployment(project, baseDir, (RemoteProjectSettings)settings,
(RemoteSdkData)getSdk().getSdkAdditionalData());
}
}
@NotNull
@Override
public ValidationResult validate(@NotNull String baseDirPath) {
if (PythonSdkType.isRemote(getSdk())) {
if (PythonRemoteInterpreterManager.getInstance() == null) {
return new ValidationResult(PythonRemoteInterpreterManager.WEB_DEPLOYMENT_PLUGIN_IS_DISABLED);
}
}
return ValidationResult.OK;
}
};
}
@Override
public void checkValid() {
super.checkValid();
Sdk sdk = getSdk();
if (isOKActionEnabled()) {
setOKActionEnabled(true);
setErrorText(null);
myFrameworkCheckbox.setVisible(false);
DirectoryProjectGenerator generator = getProjectGenerator();
final boolean isPy3k = sdk != null && PythonSdkType.getLanguageLevelForSdk(sdk).isPy3K();
if (sdk != null && PythonSdkType.isRemote(sdk) && !acceptsRemoteSdk(generator)) {
setOKActionEnabled(false);
setErrorText("Please choose a local interpreter");
}
else if (generator instanceof PyFrameworkProjectGenerator) {
PyFrameworkProjectGenerator frameworkProjectGenerator = (PyFrameworkProjectGenerator)generator;
String frameworkName = frameworkProjectGenerator.getFrameworkTitle();
if (sdk != null && !isFrameworkInstalled(sdk)) {
final PyPackageManagerImpl packageManager = (PyPackageManagerImpl)PyPackageManager.getInstance(sdk);
final boolean onlyWithCache =
PythonSdkFlavor.getFlavor(sdk) instanceof JythonSdkFlavor || PythonSdkFlavor.getFlavor(sdk) instanceof PyPySdkFlavor;
try {
if (onlyWithCache && packageManager.cacheIsNotNull() || !onlyWithCache) {
final PyPackage pip = packageManager.findPackage("pip");
myFrameworkCheckbox.setText("Install " + frameworkName);
myFrameworkCheckbox.setMnemonic(frameworkName.charAt(0));
myFrameworkCheckbox.setVisible(pip != null);
if (!myInstallFrameworkChanged) {
myFrameworkCheckbox.setSelected(pip != null);
}
}
}
catch (PyExternalProcessException e) {
myFrameworkCheckbox.setVisible(false);
}
if (!myFrameworkCheckbox.isSelected()) {
setErrorText("No " + frameworkName + " support installed in selected interpreter");
setOKActionEnabled(false);
}
}
if (isPy3k && !((PyFrameworkProjectGenerator)generator).supportsPython3()) {
setErrorText(frameworkName + " is not supported for the selected interpreter");
setOKActionEnabled(false);
}
}
if (sdk == null) {
setOKActionEnabled(false);
setErrorText("No Python interpreter selected");
}
}
}
private void selectCompatiblePython() {
DirectoryProjectGenerator generator = getProjectGenerator();
if (generator instanceof PyFrameworkProjectGenerator && !((PyFrameworkProjectGenerator)generator).supportsPython3()) {
Sdk sdk = getSdk();
if (sdk != null && PythonSdkType.getLanguageLevelForSdk(sdk).isPy3K()) {
Sdk python2Sdk = PythonSdkType.findPython2Sdk(null);
if (python2Sdk != null) {
mySdkCombo.getComboBox().setSelectedItem(python2Sdk);
mySdkCombo.getComboBox().repaint();
}
}
}
}
private boolean isFrameworkInstalled(Sdk sdk) {
PyFrameworkProjectGenerator projectGenerator = (PyFrameworkProjectGenerator)getProjectGenerator();
return projectGenerator != null && projectGenerator.isFrameworkInstalled(myProject, sdk);
}
private static boolean acceptsRemoteSdk(DirectoryProjectGenerator generator) {
if (generator instanceof PyFrameworkProjectGenerator) {
return ((PyFrameworkProjectGenerator)generator).acceptsRemoteSdk();
}
return true;
}
public boolean installFramework() {
return myFrameworkCheckbox.isSelected() && myFrameworkCheckbox.isVisible();
}
public Sdk getSdk() {
return (Sdk)mySdkCombo.getComboBox().getSelectedItem();
}
}