Merge remote-tracking branch 'origin/master'
@@ -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
|
||||
|
||||
@@ -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") }
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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="&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="&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="&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="&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&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="&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 &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 &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="&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="&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="&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="<html><a href="#">Remove association</a>"/>
|
||||
<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();
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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'
|
||||
)
|
||||
|
After Width: | Height: | Size: 386 B |
|
After Width: | Height: | Size: 1007 B |
|
After Width: | Height: | Size: 324 B |
|
After Width: | Height: | Size: 866 B |
|
After Width: | Height: | Size: 197 B |
|
After Width: | Height: | Size: 224 B |
|
After Width: | Height: | Size: 303 B |
|
After Width: | Height: | Size: 534 B |
|
After Width: | Height: | Size: 499 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 469 B |
|
After Width: | Height: | Size: 880 B |
|
After Width: | Height: | Size: 209 B |
|
After Width: | Height: | Size: 342 B |
|
After Width: | Height: | Size: 204 B |
|
After Width: | Height: | Size: 318 B |
|
After Width: | Height: | Size: 191 B |
|
After Width: | Height: | Size: 265 B |
|
After Width: | Height: | Size: 694 B |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 700 B |
|
After Width: | Height: | Size: 682 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 682 B |
|
After Width: | Height: | Size: 687 B |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 668 B |
|
After Width: | Height: | Size: 697 B |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 628 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 393 B |
|
After Width: | Height: | Size: 981 B |
|
After Width: | Height: | Size: 715 B |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1020 B |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 715 B |
|
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>
|
||||