Merge remote-tracking branch 'origin/master'

This commit is contained in:
Dmitry Trofimov
2013-09-02 15:41:49 +02:00
243 changed files with 4929 additions and 62 deletions
-48
View File
@@ -1,61 +1,13 @@
htmltools
JavaScriptLanguage
JavaScriptDebugger
FirefoxConnector
ChromeConnector
python-javascript-debugger
cvsIntegration
cvs-core
cvs-plugin
javacvs-src
smartcvs-src
PerforceIntegration
Perforce
perforce_util
svn4idea
git4idea
CSS
css-api
JSInspections
JSIntentionPowerPack
less
sass
haml
haml-plugin
hg4idea
tasks
tasks-core
tasks-api
github
webDeployment
jdbc-console
django-db-config
database-impl
DatabaseSupport
database-plugin
sql
sql-plugin
coffeescript
remote-run
python-remote-interpreter
vagrant
diagram-api
uml
python-uml
localization
python-localization
rest
python-rest
pycharm-flask
pycharm-numpy
textmate
restClient
puppet
fileWatcher
terminal
IntelliLang
IntelliLang-xml
IntelliLang-js
IntelliLang-python
ini4idea
stylus
+9 -5
View File
@@ -14,6 +14,7 @@ ant.xmlproperty(file: "$home/python/resources/idea/PythonApplicationInfo.xml", c
setProperty("system_selector", "PyCharm${p("component.version.major")}0")
setProperty("ch", "$home/community")
setProperty("pythonCommunityHome", "$home/python/community")
setProperty("dryRun", false)
setProperty("jdk16", guessJdk())
@@ -26,8 +27,8 @@ private List<String> pycharmPlatformApiModules() {
private List pycharmImplementationModules() { //modules to put into pycharm.jar
return ["yaml", "graph", "coverage-common", "python-community", "python", "python-ide", "python-openapi", "python-psi-api",
"duplicates", "duplicates-xml"]
return ["yaml", "graph", "coverage-common", "python-community", "python", "python-ide", "python-ide-community",
"python-openapi", "python-psi-api", "duplicates", "duplicates-xml"]
}
class Paths {
@@ -137,7 +138,8 @@ target('default': "Build artifacts") {
def launcher = "${paths.distWin}/bin/pycharm.exe"
List resourcePaths = ["$home/community/community-resources/src",
"$home/community/platform/icons/src",
"$home/python/resources"]
"$home/python/resources",
"$pythonCommunityHome/resources"]
buildWinLauncher("$home/community", "$home/community/bin/WinLauncher/WinLauncher.exe", launcher,
appInfoFile(), "$home/python/build/pycharm_launcher.properties", system_selector, resourcePaths)
signExe(launcher)
@@ -214,7 +216,7 @@ private scramble() {
}
private String appInfoFile() {
return "$home/out/pycharm/classes/production/python-ide/idea/PythonApplicationInfo.xml"
return "$home/out/pycharm/classes/production/python-ide-community/idea/PythonApplicationInfo.xml"
}
private layoutFull(Map args, String target, Set usedJars) {
@@ -267,13 +269,15 @@ private layoutFull(Map args, String target, Set usedJars) {
fileset(dir: "$home/python/resources") {
include(name: "**/tips/**")
}
fileset(dir: "$pythonCommunityHome/resources") {
include(name: "**/tips/**")
}
module("platform-resources-en") {
ant.patternset {
exclude(name: "tips/images/switcher.png")
exclude(name: "tips/images/navigateToFilePath.gif")
}
}
zipfileset(dir: "$home/python/resources/tips", prefix: "tips")
}
jar("icons.jar") { module("icons") }
+374
View File
@@ -0,0 +1,374 @@
import org.jetbrains.jps.LayoutInfo
import static org.jetbrains.jps.idea.IdeaProjectLoader.guessHome
includeTargets << new File("${guessHome(this as Script)}/community/build/scripts/utils.gant")
includeTargets << new File("${guessHome(this)}/build/scripts/libLicenses.gant")
includeTargets << new File("${guessHome(this)}/python/build/python_common.gant")
requireProperty("buildNumber", requireProperty("build.number", snapshot))
setProperty("ch", "$home/community")
setProperty("pythonCommunityHome", "$home/python/community")
// load ApplicationInfo.xml properties
ant.xmlproperty(file: "$pythonCommunityHome/resources/idea/PyCharmCoreApplicationInfo.xml", collapseAttributes: "true")
setProperty("system_selector", "PyCharm${p("component.version.major")}0")
setProperty("dryRun", false)
setProperty("jdk16", guessJdk())
//modules to compile
setProperty("pluginFilter", new File("$pythonCommunityHome/build/plugin-list.txt").readLines())
private List<String> pycharmPlatformApiModules() {
return [platformApiModules, "dom-openapi"].flatten()
}
private List pycharmImplementationModules() { //modules to put into pycharm.jar
return [platformImplementationModules, "dom-impl", "python-community", "python-ide-community", "python-openapi", "python-psi-api"]
}
class Paths {
final sandbox
final distAll
final distWin
final distMac
final distUnix
final artifacts
final ideaSystem
final ideaConfig
def Paths(String home) {
sandbox = "$home/out/pycharmCE"
distAll = "$sandbox/layout"
distWin = "$sandbox/win"
distMac = "$sandbox/mac"
distUnix = "$sandbox/unix"
artifacts = "$home/out/pycharmCE/artifacts"
ideaSystem = "$sandbox/system"
ideaConfig = "$sandbox/config"
}
}
setProperty("paths", new Paths(home))
setProperty("buildName", "PC-$buildNumber")
target('default': "Build artifacts") {
def modules = [
"python-pydev", "colorSchemes", pycharmPlatformApiModules(), pycharmImplementationModules(), pluginFilter
].flatten()
loadProject()
projectBuilder.stage("Cleaning up sandbox folder")
projectBuilder.targetFolder = "${paths.sandbox}/classes"
projectBuilder.dryRun = dryRun
if (!dryRun) {
forceDelete(paths.sandbox)
ant.mkdir(dir: paths.sandbox)
}
ant.tstamp() {
format(property: "todayYear", pattern: "yyyy")
}
ant.patternset(id: "resources.included") {
include(name: "**/*.properties")
include(name: "fileTemplates/**/*")
include(name: "inspectionDescriptions/**/*")
include(name: "intentionDescriptions/**/*")
include(name: "tips/**/*")
include(name: "search/**/*")
}
ant.patternset(id: "resources.excluded") {
exclude(name: "**/*.properties")
exclude(name: "fileTemplates/**/*")
exclude(name: "fileTemplates")
exclude(name: "inspectionDescriptions/**/*")
exclude(name: "inspectionDescriptions")
exclude(name: "intentionDescriptions/**/*")
exclude(name: "intentionDescriptions")
exclude(name: "tips/**/*")
exclude(name: "tips")
}
zipSources(home, paths.artifacts)
def usedJars = buildModules(modules, ["python/lib"])
buildSearchableOptions("${projectBuilder.moduleOutput(findModule("platform-resources"))}/search", [], {
projectBuilder.moduleRuntimeClasspath(findModule("main_pycharm_ce"), false).each {
ant.pathelement(location: it)
}
}, "-Didea.platform.prefix=PyCharmCore -Didea.no.jre.check=true")
if (!dryRun) {
wireBuildDate(buildName, appInfoFile())
}
Map args = [
buildNumber: buildName,
system_selector: system_selector,
ide_jvm_args: "-Didea.platform.prefix=PyCharmCore -Didea.no.jre.check=true"]
LayoutInfo layoutInfo = layoutFull(args, paths.distAll, usedJars)
generateLicensesTable("$paths.artifacts/third-party-libraries.txt", layoutInfo.usedModules);
def egg = buildDebuggerEgg(paths.sandbox, "$home/python", buildName)
ant.copy(file: egg, todir: paths.distAll)
def eggPy3k = buildDebuggerEggPy3K(paths.sandbox, "$home/python", buildName)
ant.copy(file: eggPy3k, todir: paths.distAll)
layoutWin(args, paths.distWin)
layoutUnix(args, paths.distUnix)
layoutMac(args, paths.distMac)
ant.echo(message: buildName, file: "${paths.sandbox}/layout/build.txt")
/*
def launcher = "${paths.distWin}/bin/pycharm.exe"
List resourcePaths = ["$home/community/community-resources/src",
"$home/community/platform/icons/src",
"$home/python/resources",
"$home/python/community/resources"]
buildWinLauncher("$home/community", "$home/community/bin/WinLauncher/WinLauncher.exe", launcher,
appInfoFile(), "$home/python/build/pycharm_launcher.properties", system_selector, resourcePaths)
signExe(launcher)
buildWinZip("${paths.artifacts}/pycharm${buildName}.zip", [paths.distAll, paths.distWin])
buildNSIS([paths.distAll, paths.distWin],
"$home/python/build/strings.nsi", "$home/python/build/paths.nsi",
"pycharm", false, true, system_selector)
String tarRoot = isEap() ? "pycharm-$buildNumber" : "pycharm-${p("component.version.major")}.${p("component.version.minor")}"
buildTarGz(tarRoot, "$paths.artifacts/pycharm${buildName}.tar", [paths.distAll, paths.distUnix])
String macAppRoot = isEap() ? "PyCharm ${p("component.version.major")}.${p("component.version.minor")} EAP.app" : "PyCharm.app"
buildMacZip(macAppRoot, "${paths.artifacts}/pycharm${buildName}.sit", [paths.distAll], paths.distMac)
signMacZip("pycharm")
buildDmg("pycharm", "${home}/python/build/DMG_background.png")
*/
}
private layoutPlugins(layouts) {
dir("plugins") {
/*
layouts.layoutPlugin("django-db-config")
layouts.layoutPlugin("python-javascript-debugger")
layouts.layoutPlugin("remote-run") {
fileset(dir: "$home/plugins/remote-run/lib") {
include(name: "jediterm-0.2.jar")
}
}
layouts.layoutPlugin("python-remote-interpreter")
layouts.layoutPlugin("vagrant") {
fileset(dir: "$home/plugins/vagrant/lib") {
include(name: "jrubyparser-0.2.jar")
}
}
layouts.layoutPlugin("python-uml")
layouts.layoutPlugin("localization")
layouts.layoutPlugin("python-localization")
layouts.layoutPlugin("rest")
layouts.layoutPlugin("python-rest")
layouts.layoutPlugin("pycharm-flask")
layouts.layoutPlugin("pycharm-numpy")
layouts.layoutPlugin("textmate") {
dir("themes") {
fileset(dir: "${home}/plugins/textmate/lib/themes/", includes: "*.tmTheme")
}
fileset(dir: "${home}/plugins/textmate/lib") {
include(name: "jcodings.jar")
include(name: "joni.jar")
}
}
layouts.layoutPlugin("puppet")
layouts.layoutPlugin("fileWatcher")
layouts.layoutPlugin("ini4idea")
*/
}
layouts.layoutPlugins()
}
private String appInfoFile() {
return "$home/out/pycharm/classes/production/python-ide-community/idea/PyCharmCoreApplicationInfo.xml"
}
private layoutFull(Map args, String target, Set usedJars) {
def openapiModules = pycharmPlatformApiModules()
def superLayouts = includeFile("$home/build/scripts/layouts.gant")
def result = layout(target) {
dir("lib") {
jar("util.jar") {
module("util")
module("util-rt")
}
jar("openapi.jar") {
openapiModules.each { module it }
}
jar("annotations.jar") { module("annotations") }
jar("extensions.jar") { module("extensions") }
jar("pycharm.jar") {
pycharmImplementationModules().each {
module(it) {
exclude(name: "**/tips/**")
}
}
}
jar("pycharm-pydev.jar") {
module("python-pydev")
}
jar("bootstrap.jar") { module("bootstrap") }
jar("resources.jar") {
module("platform-resources")
module("colorSchemes")
}
jar("forms_rt.jar") {
module("forms_rt")
}
//noinspection GroovyAssignabilityCheck
jar([name: "resources_en.jar", duplicate: "preserve"]) {
// custom resources should go first
fileset(dir: "$home/python/resources") {
include(name: "**/tips/**")
}
fileset(dir: "$home/python/community/resources") {
include(name: "**/tips/**")
}
module("platform-resources-en") {
ant.patternset {
exclude(name: "tips/images/switcher.png")
exclude(name: "tips/images/navigateToFilePath.gif")
}
}
}
jar("icons.jar") { module("icons") }
jar("boot.jar") { module("boot") }
usedJars.each {
fileset(file: it)
}
dir("ext") {
fileset(dir: "$home/community/lib") {
include(name: "cglib*.jar")
}
}
dir("src") {
fileset(dir: "$home/community/lib/src") {
include(name: "trove4j_changes.txt")
include(name: "trove4j_src.jar")
}
jar("pycharm-pydev-src.zip") {
fileset(dir: "$home/python/pydevSrc")
}
jar("pycharm-openapi-src.zip") {
fileset(dir: "$home/python/openapi/src")
fileset(dir: "$home/python/psi-api/src")
}
}
}
dir("help") {
fileset(dir: "$home/python/help") {
include(name: "*.pdf")
}
}
dir("helpers") {
fileset(dir: "$home/python/helpers")
}
dir("license") {
fileset(dir: "$home/community/license")
}
layoutPlugins(superLayouts)
dir("bin") {
fileset(dir: "$home/community/bin") {
exclude(name: "appletviewer.policy")
include(name: "*.*")
}
}
}
patchPropertiesFile(target, args + [appendices: ["$home/build/conf/ideaJNC.properties"]])
return result
}
private layoutWin(Map args, String target) {
layout(target) {
dir("bin") {
fileset(dir: "$home/community/bin/win") {
exclude(name: "breakgen*")
}
}
dir("skeletons") {
fileset(dir: "$home/python/skeletons") {
include(name: "skeletons-win*.zip")
}
}
}
winScripts(target, "$home/community", "pycharm.bat", args)
winVMOptions(target, args.system_selector, "pycharm.exe")
}
private layoutUnix(Map args, String target) {
layout(target) {
dir("bin") {
fileset(dir: "$home/community/bin/linux") {
exclude(name: "libbreakgen*")
}
}
}
ant.copy(file: "$home/python/resources/PyCharm_128.png", tofile: "$target/bin/pycharm.png")
unixScripts(target, "$home/community", "pycharm.sh", args)
unixVMOptions(target, "pycharm")
}
private layoutMac(Map _args, String target) {
layout(target) {
dir("bin") {
fileset(dir: "$home/bin") {
include(name: "*.jnilib")
}
}
dir("skeletons") {
fileset(dir: "$home/python/skeletons") {
include(name: "skeletons-mac*.zip")
}
}
}
Map args = new HashMap(_args)
args.icns = "$home/python/resources/PyCharm.icns"
args.bundleIdentifier = "com.jetbrains.pycharm"
args.platform_prefix = "Python"
args.help_id = "PY"
args."idea.properties.path" = "${paths.distAll}/bin/idea.properties"
args."idea.properties" = ["idea.no.jre.check": true, "ide.mac.useNativeClipboard": "false"];
layoutMacApp(target, "$home/community", args)
}
+15
View File
@@ -0,0 +1,15 @@
<?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" />
<sourceFolder url="file://$MODULE_DIR$" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Groovy" level="project" />
<orderEntry type="module" module-name="jps-standalone-builder" />
</component>
</module>
+4
View File
@@ -333,6 +333,10 @@ target(name: "compile", description: "Compile module python") {
patternset(refid: "resources.pt")
type(type: "file")
}
fileset(dir: "${pluginHome}/community/resources") {
patternset(refid: "resources.pt")
type(type: "file")
}
connectorPlugins.each {
fileset(dir: "${pluginHome}/${it}/resources") {
patternset(refid: "resources.pt")
+21
View File
@@ -0,0 +1,21 @@
<?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>
<content url="file://$MODULE_DIR$/../../resources">
<sourceFolder url="file://$MODULE_DIR$/../../resources" 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();
}
}
+2 -2
View File
@@ -5,7 +5,6 @@
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="bootstrap" />
<orderEntry type="module" module-name="python-tests" />
<orderEntry type="module" module-name="colorSchemes" />
<orderEntry type="module" module-name="cvs-plugin" />
<orderEntry type="module" module-name="hg4idea" />
@@ -14,11 +13,12 @@
<orderEntry type="module" module-name="relaxng" />
<orderEntry type="module" module-name="github" />
<orderEntry type="module" module-name="rest" />
<orderEntry type="module" module-name="python-rest" />
<orderEntry type="module" module-name="pycharm-numpy" />
<orderEntry type="module" module-name="python-helpers" />
<orderEntry type="module" module-name="terminal" />
<orderEntry type="module" module-name="ini4idea" />
<orderEntry type="module" module-name="python-ide-community" />
<orderEntry type="module" module-name="platform-main" />
</component>
</module>
@@ -5,7 +5,6 @@ import com.intellij.openapi.fileTypes.FileTypeConsumer;
import com.intellij.openapi.fileTypes.FileTypeFactory;
import com.intellij.ultimate.PluginVerifier;
import com.intellij.ultimate.UltimateVerifier;
import com.jetbrains.cython.CythonFileType;
import com.jetbrains.pyqt.QtUIFileType;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -22,7 +21,6 @@ public class PythonFileTypeFactory extends FileTypeFactory {
public void createFileTypes(@NonNls @NotNull final FileTypeConsumer consumer) {
consumer.consume(PythonFileType.INSTANCE, "py;pyw;");
consumer.consume(CythonFileType.INSTANCE, "pyx;pxd;pxi;");
consumer.consume(QtUIFileType.INSTANCE, "ui");
consumer.consume(XmlFileType.INSTANCE, "qrc");
}
+1
View File
@@ -4,6 +4,7 @@
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/resources" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
+1 -3
View File
@@ -5,9 +5,6 @@
<content url="file://$MODULE_DIR$/ideSrc">
<sourceFolder url="file://$MODULE_DIR$/ideSrc" isTestSource="false" />
</content>
<content url="file://$MODULE_DIR$/resources">
<sourceFolder url="file://$MODULE_DIR$/resources" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="platform-impl" />
@@ -22,6 +19,7 @@
<orderEntry type="module" module-name="relaxng" scope="RUNTIME" />
<orderEntry type="library" name="XmlRPC" level="project" />
<orderEntry type="module" module-name="webide-api" />
<orderEntry type="module" module-name="python-ide-community" exported="" />
</component>
</module>
@@ -0,0 +1,68 @@
<?xml version='1.0'?>
<list>
<option name="MAKO.SUBSTITUTION">
<value>
<option name="BACKGROUND" value="232364" />
<option name="EFFECT_TYPE" value="-1" />
</value>
</option>
<option name="MAKO.TAG">
<value>
<option name="EFFECT_TYPE" value="-1" />
</value>
</option>
<option name="PY.CLASS_DEFINITION">
<value>
<option name="FONT_TYPE" value="1" />
<option name="EFFECT_TYPE" value="1" />
</value>
</option>
<option name="PY.DECORATOR">
<value>
<option name="FOREGROUND" value="bbb529" />
<option name="EFFECT_TYPE" value="1" />
</value>
</option>
<option name="PY.FUNC_DEFINITION">
<value>
<option name="FONT_TYPE" value="1" />
<option name="EFFECT_TYPE" value="1" />
</value>
</option>
<option name="PY.KEYWORD">
<value>
<option name="FOREGROUND" value="cc7832" />
<option name="FONT_TYPE" value="1" />
</value>
</option>
<option name="PY.KEYWORD_ARGUMENT">
<value>
<option name="FOREGROUND" value="aa4926" />
</value>
</option>
<option name="PY.PREDEFINED_DEFINITION">
<value>
<option name="FOREGROUND" value="B200B2" />
</value>
</option>
<option name="PY.PREDEFINED_USAGE">
<value>
<option name="FOREGROUND" value="B200B2" />
</value>
</option>
<option name="PY.SELF_PARAMETER">
<value>
<option name="FOREGROUND" value="94558D" />
</value>
</option>
<option name="PY.STRING.B">
<value>
<option name="FOREGROUND" value="a5c261" />
</value>
</option>
<option name="PY.STRING.U">
<value>
<option name="FOREGROUND" value="008080" />
</value>
</option>
</list>
@@ -0,0 +1,62 @@
<?xml version='1.0'?>
<list>
<option name="MAKO.SUBSTITUTION">
<value>
<option name="BACKGROUND" value="E6E6FA" />
<option name="EFFECT_TYPE" value="-1" />
</value>
</option>
<option name="MAKO.TAG">
<value>
<option name="EFFECT_TYPE" value="-1" />
</value>
</option>
<option name="PY.BUILTIN_NAME">
<value>
<option name="FOREGROUND" value="80" />
</value>
</option>
<option name="PY.CLASS_DEFINITION">
<value>
<option name="FOREGROUND" value="000000" />
<option name="EFFECT_TYPE" value="1" />
</value>
</option>
<option name="PY.DECORATOR">
<value>
<option name="FOREGROUND" value="0000B2" />
</value>
</option>
<option name="PY.FUNC_DEFINITION">
<value>
<option name="FOREGROUND" value="000000" />
<option name="EFFECT_TYPE" value="1" />
</value>
</option>
<option name="PY.KEYWORD_ARGUMENT">
<value>
<option name="FOREGROUND" value="660099" />
</value>
</option>
<option name="PY.PREDEFINED_DEFINITION">
<value>
<option name="FOREGROUND" value="B200B2" />
</value>
</option>
<option name="PY.PREDEFINED_USAGE">
<value>
<option name="FOREGROUND" value="B200B2" />
</value>
</option>
<option name="PY.SELF_PARAMETER">
<value>
<option name="FOREGROUND" value="94558D" />
</value>
</option>
<option name="PY.STRING.U">
<value>
<option name="FOREGROUND" value="008080" />
<option name="FONT_TYPE" value="1" />
</value>
</option>
</list>
@@ -0,0 +1 @@
__author__ = '$USER'
@@ -0,0 +1,10 @@
__author__ = '$USER'
import unittest
class MyTestCase(unittest.TestCase):
def test_something(self):
self.assertEqual(True, False)
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,12 @@
from distutils.core import setup
setup(
name='$Package_name',
version='$Version',
packages=$PackageList,$PackageDirs
url='$URL',
license='$License',
author='$Author',
author_email='$Author_Email',
description='$Description'
)
Binary file not shown.

After

Width:  |  Height:  |  Size: 386 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1007 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 866 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 303 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 534 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 499 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 469 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 880 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 694 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 700 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 682 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 682 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 687 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 668 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 697 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 393 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 981 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 715 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1020 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 715 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

@@ -0,0 +1,5 @@
<html>
<body>
This inspection highlights unresolved buildout parts.
</body>
</html>
@@ -0,0 +1,7 @@
<html>
<body>
<span style="font-family: verdana,serif;">
This inspection detects when there aren't all abstract properties/methods are defined in subclass
</span>
</body>
</html>
@@ -0,0 +1,7 @@
<html>
<body>
<span style="font-family: verdana,serif;">
This inspection highlights situations, where argument passed to function is equal to default parameter value
</span>
</body>
</html>
@@ -0,0 +1,8 @@
<html>
<body>
<span style="font-family: verdana,serif;">
This inspection reports discrepancies between declared parameters and actual arguments, as well as
incorrect arguments (e.g. duplicate named arguments) and incorrect argument order. Decorators are analyzed, too.
</span>
</body>
</html>
@@ -0,0 +1,7 @@
<html>
<body>
<span style="font-family: verdana,serif; font-size: smaller;">
This inspection detects instance attribute definition outside __init__ method
</span>
</body>
</html>
@@ -0,0 +1,7 @@
<html>
<body>
<span style="font-family: verdana,serif;">
This inspection highlights assignment that can be replaced with augmented assignment.
</span>
</body>
</html>

Some files were not shown because too many files have changed in this diff Show More