mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
applied patch for student-python dependencies sincerely provided by Greg Shrago
new project panel steps and generator moved to the python-community-configure so it can be used in other modules without python-community-ide dependency
This commit is contained in:
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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.steps;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.util.projectWizard.ProjectSettingsStepBase;
|
||||
import com.intellij.ide.util.projectWizard.actions.ProjectSpecificAction;
|
||||
import com.intellij.openapi.actionSystem.DefaultActionGroup;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.platform.CustomStepProjectGenerator;
|
||||
import com.intellij.platform.DirectoryProjectGenerator;
|
||||
import com.intellij.util.NullableConsumer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PluginSpecificProjectsStep extends DefaultActionGroup implements DumbAware {
|
||||
|
||||
public PluginSpecificProjectsStep(@NotNull final NullableConsumer<ProjectSettingsStepBase> callback,
|
||||
@NotNull final List<DirectoryProjectGenerator> projectGenerators) {
|
||||
super("Plugin-specific", true);
|
||||
getTemplatePresentation().setIcon(AllIcons.Nodes.PluginLogo);
|
||||
for (DirectoryProjectGenerator generator : projectGenerators) {
|
||||
ProjectSettingsStepBase step = generator instanceof CustomStepProjectGenerator ?
|
||||
((ProjectSettingsStepBase)((CustomStepProjectGenerator)generator).createStep(generator, callback)) :
|
||||
new ProjectSpecificSettingsStep(generator, callback);
|
||||
|
||||
ProjectSpecificAction action = new ProjectSpecificAction(generator, step);
|
||||
addAll(action.getChildren(null));
|
||||
}
|
||||
}
|
||||
}
|
||||
+461
@@ -0,0 +1,461 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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.steps;
|
||||
|
||||
import com.intellij.execution.ExecutionException;
|
||||
import com.intellij.facet.ui.ValidationResult;
|
||||
import com.intellij.ide.util.projectWizard.ProjectSettingsStepBase;
|
||||
import com.intellij.ide.util.projectWizard.WebProjectTemplate;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectManager;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.ui.*;
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.platform.DirectoryProjectGenerator;
|
||||
import com.intellij.ui.DocumentAdapter;
|
||||
import com.intellij.ui.HideableDecorator;
|
||||
import com.intellij.ui.TextAccessor;
|
||||
import com.intellij.util.NullableConsumer;
|
||||
import com.intellij.util.PathUtil;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.intellij.util.ui.update.UiNotifyConnector;
|
||||
import com.jetbrains.python.configuration.PyConfigurableInterpreterList;
|
||||
import com.jetbrains.python.configuration.VirtualEnvProjectFilter;
|
||||
import com.jetbrains.python.newProject.PyFrameworkProjectGenerator;
|
||||
import com.jetbrains.python.newProject.PythonProjectGenerator;
|
||||
import com.jetbrains.python.packaging.PyPackage;
|
||||
import com.jetbrains.python.packaging.PyPackageManager;
|
||||
import com.jetbrains.python.packaging.PyPackageUtil;
|
||||
import com.jetbrains.python.remote.PyProjectSynchronizer;
|
||||
import com.jetbrains.python.remote.PythonRemoteInterpreterManager;
|
||||
import com.jetbrains.python.sdk.PySdkUtil;
|
||||
import com.jetbrains.python.sdk.PythonSdkType;
|
||||
import icons.PythonIcons;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ProjectSpecificSettingsStep extends ProjectSettingsStepBase implements DumbAware {
|
||||
private static final Logger LOGGER = Logger.getInstance(ProjectSpecificSettingsStep.class);
|
||||
private PythonSdkChooserCombo mySdkCombo;
|
||||
private boolean myInstallFramework;
|
||||
private Sdk mySdk;
|
||||
/**
|
||||
* For remote projects path for project on remote side
|
||||
*/
|
||||
private PyRemotePathField myRemotePathField;
|
||||
/**
|
||||
* If remote path required for project creation or not
|
||||
*/
|
||||
private boolean myRemotePathRequired;
|
||||
|
||||
public ProjectSpecificSettingsStep(@NotNull final DirectoryProjectGenerator projectGenerator,
|
||||
@NotNull final NullableConsumer<ProjectSettingsStepBase> callback) {
|
||||
super(projectGenerator, callback);
|
||||
}
|
||||
|
||||
private void acceptsSdk(@NotNull final DirectoryProjectGenerator<?> generator,
|
||||
@NotNull final Sdk sdk,
|
||||
@NotNull final File projectDirectory) throws PythonProjectGenerator.PyNoProjectAllowedOnSdkException {
|
||||
if (generator instanceof PythonProjectGenerator) {
|
||||
((PythonProjectGenerator<?>)generator).checkProjectCanBeCreatedOnSdk(sdk, projectDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JPanel createAndFillContentPanel() {
|
||||
if (myProjectGenerator instanceof PythonProjectGenerator) {
|
||||
// Allow generator to display custom error
|
||||
((PythonProjectGenerator<?>)myProjectGenerator).setErrorCallback(this::setErrorText);
|
||||
}
|
||||
return createContentPanelWithAdvancedSettingsPanel();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected JPanel createAdvancedSettings() {
|
||||
JComponent advancedSettings = null;
|
||||
if (myProjectGenerator instanceof PythonProjectGenerator) {
|
||||
advancedSettings = ((PythonProjectGenerator)myProjectGenerator).getSettingsPanel(myProjectDirectory);
|
||||
}
|
||||
else if (myProjectGenerator instanceof WebProjectTemplate) {
|
||||
advancedSettings = ((WebProjectTemplate)myProjectGenerator).getPeer().getComponent();
|
||||
}
|
||||
if (advancedSettings != null) {
|
||||
final JPanel jPanel = new JPanel(new VerticalFlowLayout());
|
||||
final HideableDecorator deco = new HideableDecorator(jPanel, "Mor&e Settings", false);
|
||||
boolean isValid = checkValid();
|
||||
deco.setOn(!isValid);
|
||||
if (myProjectGenerator instanceof PythonProjectGenerator && !deco.isExpanded()) {
|
||||
final ValidationResult result = ((PythonProjectGenerator)myProjectGenerator).warningValidation(getSdk());
|
||||
deco.setOn(!result.isOk());
|
||||
}
|
||||
deco.setContentComponent(advancedSettings);
|
||||
return jPanel;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Sdk getSdk() {
|
||||
if (!(myProjectGenerator instanceof PythonProjectGenerator)) return null;
|
||||
if (mySdk != null) return mySdk;
|
||||
if (((PythonProjectGenerator)myProjectGenerator).hideInterpreter()) return null;
|
||||
return (Sdk)mySdkCombo.getComboBox().getSelectedItem();
|
||||
}
|
||||
|
||||
public void setSdk(final Sdk sdk) {
|
||||
mySdk = sdk;
|
||||
}
|
||||
|
||||
public boolean installFramework() {
|
||||
return myInstallFramework;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerValidators() {
|
||||
super.registerValidators();
|
||||
if (myProjectGenerator instanceof PythonProjectGenerator && !((PythonProjectGenerator)myProjectGenerator).hideInterpreter()) {
|
||||
myLocationField.getTextField().getDocument().addDocumentListener(new DocumentAdapter() {
|
||||
@Override
|
||||
protected void textChanged(DocumentEvent e) {
|
||||
final String path = myLocationField.getText().trim();
|
||||
((PythonProjectGenerator)myProjectGenerator).locationChanged(PathUtil.getFileName(path));
|
||||
}
|
||||
});
|
||||
|
||||
mySdkCombo.getComboBox().addItemListener(e -> {
|
||||
if (e.getStateChange() == ItemEvent.SELECTED) {
|
||||
final Runnable checkValidOnSwing = () -> ApplicationManager.getApplication().invokeLater(this::checkValid);
|
||||
ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> {
|
||||
try {
|
||||
// Refresh before validation to make sure no stale data
|
||||
final Sdk sdk = getSdk();
|
||||
if (sdk == null) {
|
||||
return;
|
||||
}
|
||||
final boolean noPackages = PyPackageManager.getInstance(sdk).refreshAndGetPackages(true).isEmpty();
|
||||
if (noPackages) {
|
||||
LOGGER.warn(String.format("No packages on %s", sdk.getHomePath()));
|
||||
}
|
||||
checkValidOnSwing.run();
|
||||
}
|
||||
catch (final ExecutionException exception) {
|
||||
LOGGER.warn(exception);
|
||||
checkValidOnSwing.run();
|
||||
}
|
||||
}, "Refreshing List of Packages, Please Wait", false, null);
|
||||
}
|
||||
});
|
||||
UiNotifyConnector.doWhenFirstShown(mySdkCombo, this::checkValid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return path for project on remote side provided by user
|
||||
*/
|
||||
@Nullable
|
||||
final String getRemotePath() {
|
||||
final PyRemotePathField field = myRemotePathField;
|
||||
return (field != null ? field.getTextField().getText() : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initGeneratorListeners() {
|
||||
super.initGeneratorListeners();
|
||||
if (myProjectGenerator instanceof PythonProjectGenerator) {
|
||||
((PythonProjectGenerator)myProjectGenerator).addSettingsStateListener(this::checkValid);
|
||||
myErrorLabel.addMouseListener(((PythonProjectGenerator)myProjectGenerator).getErrorLabelMouseListener());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkValid() {
|
||||
myInstallFramework = false;
|
||||
if (!super.checkValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (myProjectGenerator instanceof PythonProjectGenerator) {
|
||||
final Sdk sdk = getSdk();
|
||||
if (sdk == null) {
|
||||
if (!((PythonProjectGenerator)myProjectGenerator).hideInterpreter()) {
|
||||
setErrorText("No Python interpreter selected");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (PythonSdkType.isInvalid(sdk)) {
|
||||
setErrorText("Choose valid python interpreter");
|
||||
return false;
|
||||
}
|
||||
final List<String> warningList = new ArrayList<>();
|
||||
final boolean isPy3k = PythonSdkType.getLanguageLevelForSdk(sdk).isPy3K();
|
||||
try {
|
||||
acceptsSdk(myProjectGenerator, sdk, new File(myLocationField.getText()));
|
||||
}
|
||||
catch (final PythonProjectGenerator.PyNoProjectAllowedOnSdkException e) {
|
||||
setErrorText(e.getMessage());
|
||||
return false;
|
||||
}
|
||||
if (myRemotePathRequired && StringUtil.isEmpty(myRemotePathField.getTextField().getText())) {
|
||||
setErrorText("Remote path not provided");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (myProjectGenerator instanceof PyFrameworkProjectGenerator) {
|
||||
PyFrameworkProjectGenerator frameworkProjectGenerator = (PyFrameworkProjectGenerator)myProjectGenerator;
|
||||
String frameworkName = frameworkProjectGenerator.getFrameworkTitle();
|
||||
if (!isFrameworkInstalled(sdk)) {
|
||||
if (PyPackageUtil.packageManagementEnabled(sdk)) {
|
||||
myInstallFramework = true;
|
||||
final List<PyPackage> packages = PyPackageUtil.refreshAndGetPackagesModally(sdk);
|
||||
if (packages == null) {
|
||||
warningList.add(frameworkName + " will be installed on the selected interpreter");
|
||||
return false;
|
||||
}
|
||||
if (!PyPackageUtil.hasManagement(packages)) {
|
||||
warningList.add("Python packaging tools and " + frameworkName + " will be installed on the selected interpreter");
|
||||
}
|
||||
else {
|
||||
warningList.add(frameworkName + " will be installed on the selected interpreter");
|
||||
}
|
||||
}
|
||||
else {
|
||||
warningList.add(frameworkName + " is not installed on the selected interpreter");
|
||||
}
|
||||
}
|
||||
final ValidationResult warningResult = ((PythonProjectGenerator)myProjectGenerator).warningValidation(sdk);
|
||||
if (!warningResult.isOk()) {
|
||||
warningList.add(warningResult.getErrorMessage());
|
||||
}
|
||||
|
||||
if (!warningList.isEmpty()) {
|
||||
final String warning = StringUtil.join(warningList, "<br/>");
|
||||
setWarningText(warning);
|
||||
}
|
||||
if (isPy3k && !((PyFrameworkProjectGenerator)myProjectGenerator).supportsPython3()) {
|
||||
setErrorText(frameworkName + " is not supported for the selected interpreter");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isFrameworkInstalled(Sdk sdk) {
|
||||
PyFrameworkProjectGenerator projectGenerator = (PyFrameworkProjectGenerator)getProjectGenerator();
|
||||
return projectGenerator != null && projectGenerator.isFrameworkInstalled(sdk);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JPanel createBasePanel() {
|
||||
if (myProjectGenerator instanceof PythonProjectGenerator) {
|
||||
final BorderLayout layout = new BorderLayout();
|
||||
|
||||
final JPanel locationPanel = new JPanel(layout);
|
||||
|
||||
final JPanel panel = new JPanel(new VerticalFlowLayout(0, 2));
|
||||
final LabeledComponent<TextFieldWithBrowseButton> location = createLocationComponent();
|
||||
|
||||
locationPanel.add(location, BorderLayout.CENTER);
|
||||
panel.add(locationPanel);
|
||||
if (((PythonProjectGenerator)myProjectGenerator).hideInterpreter()) {
|
||||
addInterpreterButton(locationPanel, location);
|
||||
}
|
||||
else {
|
||||
final LabeledComponent<PythonSdkChooserCombo> labeled = createInterpreterCombo();
|
||||
UIUtil.mergeComponentsWithAnchor(labeled, location);
|
||||
panel.add(labeled);
|
||||
}
|
||||
|
||||
final PythonRemoteInterpreterManager remoteInterpreterManager = PythonRemoteInterpreterManager.getInstance();
|
||||
|
||||
final Sdk sdk = getSdk();
|
||||
if (remoteInterpreterManager != null && sdk != null) {
|
||||
createRemotePathField(panel, remoteInterpreterManager);
|
||||
}
|
||||
|
||||
|
||||
final JPanel basePanelExtension = ((PythonProjectGenerator)myProjectGenerator).extendBasePanel();
|
||||
if (basePanelExtension != null) {
|
||||
panel.add(basePanelExtension);
|
||||
}
|
||||
return panel;
|
||||
}
|
||||
|
||||
return super.createBasePanel();
|
||||
}
|
||||
|
||||
private void createRemotePathField(@NotNull final JPanel panelToAddField,
|
||||
@NotNull final PythonRemoteInterpreterManager remoteInterpreterManager) {
|
||||
myRemotePathField = new PyRemotePathField();
|
||||
|
||||
myRemotePathField.addActionListener(e -> {
|
||||
final Sdk currentSdk = getSdk();
|
||||
if (!PySdkUtil.isRemote(currentSdk)) {
|
||||
return;
|
||||
}
|
||||
// If chosen SDK is remote then display
|
||||
|
||||
final Pair<Supplier<String>, JPanel> browserForm;
|
||||
try {
|
||||
browserForm = remoteInterpreterManager.createServerBrowserForm(currentSdk);
|
||||
}
|
||||
catch (final ExecutionException | InterruptedException ex) {
|
||||
Logger.getInstance(ProjectSpecificSettingsStep.class).warn("Failed to create server browse button", ex);
|
||||
JBPopupFactory.getInstance().createMessage("Failed to browse remote server. Make sure you have permissions. ").show(panelToAddField);
|
||||
return;
|
||||
}
|
||||
if (browserForm != null) {
|
||||
browserForm.second.setVisible(true);
|
||||
final DialogWrapper wrapper = new MyRemoteServerBrowserDialog(browserForm.second);
|
||||
if (wrapper.showAndGet()) {
|
||||
myRemotePathField.getTextField().setText(browserForm.first.get());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
mySdkCombo.addChangedListener(e -> configureMappingField(remoteInterpreterManager));
|
||||
panelToAddField.add(myRemotePathField.getMainPanel());
|
||||
myRemotePathField.addTextChangeListener(() -> checkValid());
|
||||
configureMappingField(remoteInterpreterManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables "remote path" based on interpreter.
|
||||
*/
|
||||
private void configureMappingField(@NotNull final PythonRemoteInterpreterManager remoteInterpreterManager) {
|
||||
if (myRemotePathField == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final JPanel mainPanel = myRemotePathField.getMainPanel();
|
||||
final PyProjectSynchronizer synchronizer = getSynchronizer(remoteInterpreterManager);
|
||||
if (synchronizer != null) {
|
||||
final String defaultRemotePath = synchronizer.getDefaultRemotePath();
|
||||
final boolean mappingRequired = defaultRemotePath != null;
|
||||
mainPanel.setVisible(mappingRequired);
|
||||
final TextAccessor textField = myRemotePathField.getTextField();
|
||||
if (mappingRequired && StringUtil.isEmpty(textField.getText())) {
|
||||
textField.setText(defaultRemotePath);
|
||||
}
|
||||
myRemotePathRequired = mappingRequired;
|
||||
}
|
||||
else {
|
||||
mainPanel.setVisible(false);
|
||||
myRemotePathRequired = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PyProjectSynchronizer getSynchronizer(@NotNull final PythonRemoteInterpreterManager manager) {
|
||||
final Sdk sdk = getSdk();
|
||||
if (sdk == null) {
|
||||
return null;
|
||||
}
|
||||
return manager.getSynchronizer(sdk);
|
||||
}
|
||||
|
||||
private void addInterpreterButton(final JPanel locationPanel, final LabeledComponent<TextFieldWithBrowseButton> location) {
|
||||
final JButton interpreterButton = new FixedSizeButton(location);
|
||||
if (SystemInfo.isMac && !UIUtil.isUnderDarcula()) {
|
||||
interpreterButton.putClientProperty("JButton.buttonType", null);
|
||||
}
|
||||
interpreterButton.setIcon(PythonIcons.Python.Python);
|
||||
interpreterButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
final DialogBuilder builder = new DialogBuilder();
|
||||
final JPanel panel = new JPanel();
|
||||
final LabeledComponent<PythonSdkChooserCombo> interpreterCombo = createInterpreterCombo();
|
||||
if (mySdk != null) {
|
||||
mySdkCombo.getComboBox().setSelectedItem(mySdk);
|
||||
}
|
||||
panel.add(interpreterCombo);
|
||||
builder.setCenterPanel(panel);
|
||||
builder.setTitle("Select Python Interpreter");
|
||||
if (builder.showAndGet()) {
|
||||
mySdk = (Sdk)mySdkCombo.getComboBox().getSelectedItem();
|
||||
}
|
||||
}
|
||||
});
|
||||
locationPanel.add(interpreterButton, BorderLayout.EAST);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private LabeledComponent<PythonSdkChooserCombo> createInterpreterCombo() {
|
||||
final Project project = ProjectManager.getInstance().getDefaultProject();
|
||||
final List<Sdk> sdks = PyConfigurableInterpreterList.getInstance(project).getAllPythonSdks();
|
||||
VirtualEnvProjectFilter.removeAllAssociated(sdks);
|
||||
Sdk compatibleSdk = sdks.isEmpty() ? null : sdks.iterator().next();
|
||||
DirectoryProjectGenerator generator = getProjectGenerator();
|
||||
if (generator instanceof PyFrameworkProjectGenerator && !((PyFrameworkProjectGenerator)generator).supportsPython3()) {
|
||||
if (compatibleSdk != null && PythonSdkType.getLanguageLevelForSdk(compatibleSdk).isPy3K()) {
|
||||
Sdk python2Sdk = PythonSdkType.findPython2Sdk(sdks);
|
||||
if (python2Sdk != null) {
|
||||
compatibleSdk = python2Sdk;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final Sdk preferred = compatibleSdk;
|
||||
mySdkCombo = new PythonSdkChooserCombo(project, sdks, sdk -> sdk == preferred);
|
||||
if (SystemInfo.isMac && !UIUtil.isUnderDarcula()) {
|
||||
mySdkCombo.putClientProperty("JButton.buttonType", null);
|
||||
}
|
||||
mySdkCombo.setButtonIcon(PythonIcons.Python.InterpreterGear);
|
||||
|
||||
return LabeledComponent.create(mySdkCombo, "Interpreter", BorderLayout.WEST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dialog to display remote server browser
|
||||
*/
|
||||
private static class MyRemoteServerBrowserDialog extends DialogWrapper {
|
||||
|
||||
private final JPanel myBrowserForm;
|
||||
|
||||
MyRemoteServerBrowserDialog(@NotNull final JPanel browserForm) {
|
||||
super(true);
|
||||
myBrowserForm = browserForm;
|
||||
init();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected JComponent createCenterPanel() {
|
||||
return myBrowserForm;
|
||||
}
|
||||
}
|
||||
}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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.steps;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.ide.util.projectWizard.AbstractNewProjectStep;
|
||||
import com.intellij.ide.util.projectWizard.ProjectSettingsStepBase;
|
||||
import com.intellij.ide.util.projectWizard.actions.ProjectSpecificAction;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.platform.DirectoryProjectGenerator;
|
||||
import com.intellij.util.NullableConsumer;
|
||||
import com.jetbrains.python.newProject.PyFrameworkProjectGenerator;
|
||||
import com.jetbrains.python.newProject.PythonProjectGenerator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class PyCharmNewProjectStep extends AbstractNewProjectStep {
|
||||
|
||||
public PyCharmNewProjectStep() {
|
||||
super(new Customization());
|
||||
}
|
||||
|
||||
public PyCharmNewProjectStep(@NotNull AbstractNewProjectStep.Customization customization) {
|
||||
super(customization);
|
||||
}
|
||||
|
||||
protected static class Customization extends AbstractNewProjectStep.Customization {
|
||||
private final List<DirectoryProjectGenerator> pluginSpecificGenerators = Lists.newArrayList();
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected NullableConsumer<ProjectSettingsStepBase> createCallback() {
|
||||
return new PythonGenerateProjectCallback();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected DirectoryProjectGenerator createEmptyProjectGenerator() {
|
||||
return new PythonBaseProjectGenerator();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected ProjectSettingsStepBase createProjectSpecificSettingsStep(@NotNull DirectoryProjectGenerator projectGenerator,
|
||||
@NotNull NullableConsumer<ProjectSettingsStepBase> callback) {
|
||||
return new ProjectSpecificSettingsStep(projectGenerator, callback);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected DirectoryProjectGenerator[] getProjectGenerators() {
|
||||
DirectoryProjectGenerator[] generators = super.getProjectGenerators();
|
||||
|
||||
Arrays.sort(generators, (o1, o2) -> {
|
||||
if (o1 instanceof PyFrameworkProjectGenerator && !(o2 instanceof PyFrameworkProjectGenerator)) return -1;
|
||||
if (!(o1 instanceof PyFrameworkProjectGenerator) && o2 instanceof PyFrameworkProjectGenerator) return 1;
|
||||
return o1.getName().compareTo(o2.getName());
|
||||
});
|
||||
return generators;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUpBasicAction(@NotNull ProjectSpecificAction projectSpecificAction, @NotNull DirectoryProjectGenerator[] generators) {
|
||||
if (generators.length == 0) {
|
||||
projectSpecificAction.setPopup(false);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public AnAction[] getActions(@NotNull DirectoryProjectGenerator generator, @NotNull NullableConsumer<ProjectSettingsStepBase> callback) {
|
||||
if (generator instanceof PythonProjectGenerator) {
|
||||
ProjectSpecificAction group =
|
||||
new ProjectSpecificAction(generator, new ProjectSpecificSettingsStep(generator, new PythonGenerateProjectCallback()));
|
||||
return group.getChildren(null);
|
||||
}
|
||||
else {
|
||||
pluginSpecificGenerators.add(generator);
|
||||
return AnAction.EMPTY_ARRAY;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public AnAction[] getExtraActions(@NotNull NullableConsumer<ProjectSettingsStepBase> callback) {
|
||||
if (!pluginSpecificGenerators.isEmpty()) {
|
||||
PluginSpecificProjectsStep step = new PluginSpecificProjectsStep(callback, pluginSpecificGenerators);
|
||||
return step.getChildren(null);
|
||||
}
|
||||
return AnAction.EMPTY_ARRAY;
|
||||
}
|
||||
}
|
||||
}
|
||||
+32
@@ -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.newProject.steps.PyRemotePathField">
|
||||
<grid id="27dc6" binding="myMainPanel" layout-manager="GridLayoutManager" row-count="2" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<xy x="20" y="20" width="500" height="400"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<vspacer id="8ed31">
|
||||
<constraints>
|
||||
<grid row="1" column="1" 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="33807" 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>
|
||||
<text value="Remote project location:"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="b1f9a" class="com.intellij.openapi.ui.TextFieldWithBrowseButton" binding="myLocationField">
|
||||
<constraints>
|
||||
<grid row="0" 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>
|
||||
</children>
|
||||
</grid>
|
||||
</form>
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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.steps;
|
||||
|
||||
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
|
||||
import com.intellij.ui.TextAccessor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
/**
|
||||
* Field for remote path with "browse" button
|
||||
*
|
||||
* @author Ilya.Kazakevich
|
||||
*/
|
||||
public final class PyRemotePathField {
|
||||
private JPanel myMainPanel;
|
||||
private TextFieldWithBrowseButton myLocationField;
|
||||
|
||||
@NotNull
|
||||
JPanel getMainPanel() {
|
||||
return myMainPanel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add listener for "browse" button
|
||||
*/
|
||||
void addActionListener(@NotNull final ActionListener listener) {
|
||||
myLocationField.addActionListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param runnable to be called when text in textfield changed
|
||||
*/
|
||||
void addTextChangeListener(@NotNull final Runnable runnable) {
|
||||
myLocationField.getTextField().getDocument().addDocumentListener(new DocumentListener() {
|
||||
@Override
|
||||
public void insertUpdate(DocumentEvent e) {
|
||||
runnable.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeUpdate(DocumentEvent e) {
|
||||
runnable.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changedUpdate(DocumentEvent e) {
|
||||
runnable.run();
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @return test field with remote path
|
||||
*/
|
||||
@NotNull
|
||||
TextAccessor getTextField() {
|
||||
return myLocationField;
|
||||
}
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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.steps;
|
||||
|
||||
import com.intellij.facet.ui.ValidationResult;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ModuleRootModificationUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.jetbrains.python.newProject.PyNewProjectSettings;
|
||||
import com.jetbrains.python.newProject.PythonProjectGenerator;
|
||||
import com.jetbrains.python.remote.PyProjectSynchronizer;
|
||||
import icons.PythonIcons;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.File;
|
||||
|
||||
public class PythonBaseProjectGenerator extends PythonProjectGenerator<PyNewProjectSettings> {
|
||||
|
||||
public PythonBaseProjectGenerator() {
|
||||
super(true);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Nls
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Pure Python";
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public JComponent getSettingsPanel(File baseDir) throws ProcessCanceledException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getProjectSettings() {
|
||||
return new PyNewProjectSettings();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Icon getLogo() {
|
||||
return PythonIcons.Python.Python_logo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureProject(@NotNull final Project project, @NotNull VirtualFile baseDir, @NotNull final PyNewProjectSettings settings,
|
||||
@NotNull final Module module, @Nullable final PyProjectSynchronizer synchronizer) {
|
||||
// Super should be called according to its contract unless we sync project explicitly (we do not, so we call super)
|
||||
super.configureProject(project, baseDir, settings, module, synchronizer);
|
||||
ApplicationManager.getApplication().runWriteAction(() -> ModuleRootModificationUtil.setModuleSdk(module, settings.getSdk()));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ValidationResult validate(@NotNull String baseDirPath) {
|
||||
/*if (PythonSdkType.isRemote(myProjectAction.getSdk())) {
|
||||
if (PythonRemoteInterpreterManager.getInstance() == null) {
|
||||
return new ValidationResult(PythonRemoteInterpreterManager.WEB_DEPLOYMENT_PLUGIN_IS_DISABLED);
|
||||
}
|
||||
}*/
|
||||
return ValidationResult.OK;
|
||||
}
|
||||
}
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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.steps;
|
||||
|
||||
import com.intellij.ide.util.projectWizard.AbstractNewProjectStep;
|
||||
import com.intellij.ide.util.projectWizard.ProjectSettingsStepBase;
|
||||
import com.intellij.ide.util.projectWizard.WebProjectTemplate;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.options.ConfigurationException;
|
||||
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.roots.ui.configuration.projectRoot.ProjectSdksModel;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.platform.DirectoryProjectGenerator;
|
||||
import com.intellij.util.BooleanFunction;
|
||||
import com.intellij.util.NullableConsumer;
|
||||
import com.jetbrains.python.configuration.PyConfigurableInterpreterList;
|
||||
import com.jetbrains.python.newProject.PyNewProjectSettings;
|
||||
import com.jetbrains.python.newProject.PythonProjectGenerator;
|
||||
import com.jetbrains.python.sdk.PyDetectedSdk;
|
||||
import com.jetbrains.python.sdk.PythonSdkAdditionalData;
|
||||
import com.jetbrains.python.sdk.PythonSdkType;
|
||||
import com.jetbrains.python.sdk.PythonSdkUpdater;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PythonGenerateProjectCallback implements NullableConsumer<ProjectSettingsStepBase> {
|
||||
private static final Logger LOG = Logger.getInstance(PythonGenerateProjectCallback.class);
|
||||
|
||||
@Override
|
||||
public void consume(@Nullable ProjectSettingsStepBase step) {
|
||||
if (!(step instanceof ProjectSpecificSettingsStep)) return;
|
||||
|
||||
final ProjectSpecificSettingsStep settingsStep = (ProjectSpecificSettingsStep)step;
|
||||
final DirectoryProjectGenerator generator = settingsStep.getProjectGenerator();
|
||||
Sdk sdk = settingsStep.getSdk();
|
||||
|
||||
if (sdk instanceof PyDetectedSdk) {
|
||||
sdk = addDetectedSdk(settingsStep, sdk);
|
||||
}
|
||||
|
||||
if (generator instanceof PythonProjectGenerator) {
|
||||
final BooleanFunction<PythonProjectGenerator> beforeProjectGenerated = ((PythonProjectGenerator)generator).beforeProjectGenerated(sdk);
|
||||
if (beforeProjectGenerated != null) {
|
||||
final boolean result = beforeProjectGenerated.fun((PythonProjectGenerator)generator);
|
||||
if (!result) {
|
||||
Messages.showWarningDialog("Project can not be generated", "Error in Project Generation");
|
||||
}
|
||||
}
|
||||
}
|
||||
final Project newProject = generateProject(settingsStep);
|
||||
if (generator instanceof PythonProjectGenerator && sdk == null) {
|
||||
final PyNewProjectSettings settings = (PyNewProjectSettings)((PythonProjectGenerator)generator).getProjectSettings();
|
||||
((PythonProjectGenerator)generator).createAndAddVirtualEnv(newProject, settings);
|
||||
sdk = settings.getSdk();
|
||||
}
|
||||
|
||||
if (newProject != null && generator instanceof PythonProjectGenerator) {
|
||||
SdkConfigurationUtil.setDirectoryProjectSdk(newProject, sdk);
|
||||
final List<Sdk> sdks = PythonSdkType.getAllSdks();
|
||||
for (Sdk s : sdks) {
|
||||
final SdkAdditionalData additionalData = s.getSdkAdditionalData();
|
||||
if (additionalData instanceof PythonSdkAdditionalData) {
|
||||
((PythonSdkAdditionalData)additionalData).reassociateWithCreatedProject(newProject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Sdk addDetectedSdk(ProjectSpecificSettingsStep settingsStep, Sdk sdk) {
|
||||
final Project project = ProjectManager.getInstance().getDefaultProject();
|
||||
final ProjectSdksModel model = PyConfigurableInterpreterList.getInstance(project).getModel();
|
||||
final String name = sdk.getName();
|
||||
VirtualFile sdkHome = ApplicationManager.getApplication().runWriteAction((Computable<VirtualFile>)() -> LocalFileSystem.getInstance().refreshAndFindFileByPath(name));
|
||||
sdk = SdkConfigurationUtil.createAndAddSDK(sdkHome.getPath(), PythonSdkType.getInstance());
|
||||
if (sdk != null) {
|
||||
PythonSdkUpdater.updateOrShowError(sdk, null, project, null);
|
||||
}
|
||||
|
||||
model.addSdk(sdk);
|
||||
settingsStep.setSdk(sdk);
|
||||
try {
|
||||
model.apply();
|
||||
}
|
||||
catch (ConfigurationException exception) {
|
||||
LOG.error("Error adding detected python interpreter " + exception.getMessage());
|
||||
}
|
||||
return sdk;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Project generateProject(@NotNull final ProjectSettingsStepBase settings) {
|
||||
final DirectoryProjectGenerator generator = settings.getProjectGenerator();
|
||||
final String location = FileUtil.expandUserHome(settings.getProjectLocation());
|
||||
return AbstractNewProjectStep.doGenerateProject(ProjectManager.getInstance().getDefaultProject(), location, generator,
|
||||
file -> computeProjectSettings(generator, (ProjectSpecificSettingsStep)settings));
|
||||
}
|
||||
|
||||
public static Object computeProjectSettings(DirectoryProjectGenerator<?> generator, final ProjectSpecificSettingsStep settings) {
|
||||
Object projectSettings = null;
|
||||
if (generator instanceof PythonProjectGenerator) {
|
||||
final PythonProjectGenerator<?> projectGenerator = (PythonProjectGenerator<?>)generator;
|
||||
projectSettings = projectGenerator.getProjectSettings();
|
||||
}
|
||||
else if (generator instanceof WebProjectTemplate) {
|
||||
projectSettings = ((WebProjectTemplate<?>)generator).getPeer().getSettings();
|
||||
}
|
||||
if (projectSettings instanceof PyNewProjectSettings) {
|
||||
final PyNewProjectSettings newProjectSettings = (PyNewProjectSettings)projectSettings;
|
||||
newProjectSettings.setSdk(settings.getSdk());
|
||||
newProjectSettings.setInstallFramework(settings.installFramework());
|
||||
newProjectSettings.setRemotePath(settings.getRemotePath());
|
||||
}
|
||||
return projectSettings;
|
||||
}
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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.steps;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.options.ConfigurationException;
|
||||
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.ui.ComboBox;
|
||||
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.PyConfigurableInterpreterList;
|
||||
import com.jetbrains.python.sdk.PySdkListCellRenderer;
|
||||
import com.jetbrains.python.sdk.PythonSdkDetailsStep;
|
||||
|
||||
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();
|
||||
private static final Logger LOG = Logger.getInstance(PythonSdkChooserCombo.class);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public PythonSdkChooserCombo(final Project project, List<Sdk> sdks, final Condition<Sdk> acceptableSdkCondition) {
|
||||
super(new ComboBox<>());
|
||||
final Sdk initialSelection = ContainerUtil.find(sdks, acceptableSdkCondition);
|
||||
final JComboBox comboBox = getComboBox();
|
||||
comboBox.setModel(new CollectionComboBoxModel(sdks, initialSelection));
|
||||
comboBox.setRenderer(new PySdkListCellRenderer(true));
|
||||
addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
showOptions(project);
|
||||
notifyChanged(e);
|
||||
}
|
||||
});
|
||||
comboBox.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
notifyChanged(e);
|
||||
updateTooltip();
|
||||
}
|
||||
});
|
||||
updateTooltip();
|
||||
}
|
||||
|
||||
private void updateTooltip() {
|
||||
final Object item = getComboBox().getSelectedItem();
|
||||
getComboBox().setToolTipText(item instanceof Sdk ? ((Sdk)item).getHomePath() : null);
|
||||
}
|
||||
|
||||
private void showOptions(final Project project) {
|
||||
final PyConfigurableInterpreterList interpreterList = PyConfigurableInterpreterList.getInstance(project);
|
||||
final Sdk[] sdks = interpreterList.getModel().getSdks();
|
||||
//noinspection unchecked
|
||||
final JComboBox<Sdk> comboBox = getComboBox();
|
||||
final Sdk oldSelectedSdk = (Sdk)comboBox.getSelectedItem();
|
||||
PythonSdkDetailsStep.show(project, sdks, null, this, getButton().getLocationOnScreen(), sdk -> {
|
||||
if (sdk == null) return;
|
||||
final ProjectSdksModel projectSdksModel = interpreterList.getModel();
|
||||
if (projectSdksModel.findSdk(sdk) == null) {
|
||||
projectSdksModel.addSdk(sdk);
|
||||
try {
|
||||
projectSdksModel.apply();
|
||||
}
|
||||
catch (ConfigurationException e) {
|
||||
LOG.error("Error adding new python interpreter " + e.getMessage());
|
||||
}
|
||||
}
|
||||
final List<Sdk> committedSdks = interpreterList.getAllPythonSdks();
|
||||
final Sdk copiedSdk = interpreterList.getModel().findSdk(sdk.getName());
|
||||
comboBox.setModel(new CollectionComboBoxModel<>(committedSdks, oldSelectedSdk));
|
||||
comboBox.setSelectedItem(copiedSdk);
|
||||
}, true);
|
||||
}
|
||||
|
||||
private void notifyChanged(ActionEvent e) {
|
||||
for (ActionListener changedListener : myChangedListeners) {
|
||||
changedListener.actionPerformed(e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
public void addChangedListener(ActionListener listener) {
|
||||
myChangedListeners.add(listener);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user