mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
initial 2-step create new project dialog in PyCharm
This commit is contained in:
@@ -15,11 +15,9 @@
|
||||
*/
|
||||
package com.intellij.ide.util.projectWizard;
|
||||
|
||||
import com.intellij.openapi.module.*;
|
||||
import com.intellij.openapi.options.ConfigurationException;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ModifiableRootModel;
|
||||
import com.intellij.openapi.roots.ui.configuration.ModulesProvider;
|
||||
import com.intellij.openapi.module.WebModuleBuilder;
|
||||
import com.intellij.openapi.module.WebModuleType;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.ui.ValidationInfo;
|
||||
import com.intellij.openapi.util.NotNullLazyValue;
|
||||
import com.intellij.platform.ProjectTemplate;
|
||||
@@ -28,7 +26,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.List;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* @author Dmitry Avdeev
|
||||
@@ -64,4 +62,16 @@ public abstract class WebProjectTemplate<T> extends WebProjectGenerator<T> imple
|
||||
public GeneratorPeer<T> getPeer() {
|
||||
return myPeerHolder.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public JComponent getSettingsPanel(File baseDir) throws ProcessCanceledException {
|
||||
return getPeer().getComponent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getProjectSettings() throws ProcessCanceledException {
|
||||
return getPeer().getSettings();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,6 +25,9 @@ import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
@@ -38,6 +41,15 @@ public interface DirectoryProjectGenerator<T> {
|
||||
@Nullable
|
||||
T showGenerationSettings(final VirtualFile baseDir) throws ProcessCanceledException;
|
||||
|
||||
@Nullable
|
||||
JComponent getSettingsPanel(final File baseDir) throws ProcessCanceledException;
|
||||
|
||||
@Nullable
|
||||
T getProjectSettings() throws ProcessCanceledException;
|
||||
|
||||
@Nullable
|
||||
Icon getIcon();
|
||||
|
||||
void generateProject(@NotNull final Project project, @NotNull final VirtualFile baseDir,
|
||||
@Nullable final T settings, @NotNull final Module module);
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2000-2013 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jetbrains.python.newProject;
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
|
||||
public class PyCharmNewProjectAction extends AnAction {
|
||||
|
||||
public void actionPerformed(final AnActionEvent e) {
|
||||
final PyCharmNewProjectDialog dlg = new PyCharmNewProjectDialog();
|
||||
dlg.show();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2000-2013 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jetbrains.python.newProject;
|
||||
|
||||
import com.intellij.openapi.actionSystem.DefaultActionGroup;
|
||||
import com.intellij.openapi.project.ProjectManager;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.wm.impl.welcomeScreen.CardActionsPanel;
|
||||
import com.jetbrains.python.newProject.actions.PyCharmNewProjectStep;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
|
||||
public class PyCharmNewProjectDialog extends DialogWrapper {
|
||||
public PyCharmNewProjectDialog() {
|
||||
super(ProjectManager.getInstance().getDefaultProject());
|
||||
setTitle(null);
|
||||
init();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected JComponent createCenterPanel() {
|
||||
final Runnable runnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
PyCharmNewProjectDialog.this.close(OK_EXIT_CODE);
|
||||
}
|
||||
};
|
||||
final DefaultActionGroup root = new PyCharmNewProjectStep(runnable);
|
||||
|
||||
return new CardActionsPanel(root) {
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
return getMinimumSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize() {
|
||||
return new Dimension(800, 500);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getHelpId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected Action[] createActions() {
|
||||
return new Action[0];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.jetbrains.python.newProject;
|
||||
|
||||
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.intellij.platform.DirectoryProjectGenerator;
|
||||
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 implements DirectoryProjectGenerator {
|
||||
@NotNull
|
||||
@Nls
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Basic project";
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Object showGenerationSettings(VirtualFile baseDir) throws ProcessCanceledException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public JComponent getSettingsPanel(File baseDir) throws ProcessCanceledException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getProjectSettings() throws ProcessCanceledException {
|
||||
return new PyNewProjectSettings();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Icon getIcon() {
|
||||
return PythonIcons.Python.Python_logo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateProject(@NotNull final Project project, @NotNull VirtualFile baseDir, final Object settings,
|
||||
@NotNull final Module module) {
|
||||
/*if (settings instanceof RemoteProjectSettings) {
|
||||
PythonRemoteInterpreterManager manager = PythonRemoteInterpreterManager.getInstance();
|
||||
assert manager != null;
|
||||
manager.createDeployment(project, baseDir, (RemoteProjectSettings)settings,
|
||||
(RemoteSdkCredentials)myProjectAction.getSdk().getSdkAdditionalData());
|
||||
}
|
||||
else */if (settings instanceof PyNewProjectSettings) {
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ModuleRootModificationUtil.setModuleSdk(module, ((PyNewProjectSettings)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;
|
||||
}
|
||||
}
|
||||
+20
-1
@@ -54,6 +54,7 @@ import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -179,6 +180,24 @@ public class PythonNewDirectoryProjectDialog extends NewDirectoryProjectDialog {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JComponent getSettingsPanel(File baseDir) throws ProcessCanceledException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Object getProjectSettings() throws ProcessCanceledException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Icon getIcon() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateProject(@NotNull final Project project,
|
||||
@NotNull VirtualFile baseDir,
|
||||
@@ -283,7 +302,7 @@ public class PythonNewDirectoryProjectDialog extends NewDirectoryProjectDialog {
|
||||
private boolean isFrameworkInstalled(Sdk sdk) {
|
||||
PyFrameworkProjectGenerator projectGenerator = (PyFrameworkProjectGenerator)getProjectGenerator();
|
||||
|
||||
return projectGenerator != null && projectGenerator.isFrameworkInstalled(myProject, sdk);
|
||||
return projectGenerator != null && projectGenerator.isFrameworkInstalled(sdk);
|
||||
}
|
||||
|
||||
private static boolean acceptsRemoteSdk(DirectoryProjectGenerator generator) {
|
||||
|
||||
+401
@@ -0,0 +1,401 @@
|
||||
package com.jetbrains.python.newProject.actions;
|
||||
|
||||
import com.intellij.facet.ui.ValidationResult;
|
||||
import com.intellij.ide.impl.ProjectUtil;
|
||||
import com.intellij.ide.util.projectWizard.WebProjectTemplate;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.Presentation;
|
||||
import com.intellij.openapi.actionSystem.impl.ActionButtonWithText;
|
||||
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
|
||||
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
|
||||
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.TextFieldWithBrowseButton;
|
||||
import com.intellij.openapi.ui.ValidationInfo;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.wm.impl.welcomeScreen.AbstractActionWithPanel;
|
||||
import com.intellij.platform.DirectoryProjectGenerator;
|
||||
import com.intellij.platform.WebProjectGenerator;
|
||||
import com.intellij.ui.DocumentAdapter;
|
||||
import com.intellij.ui.JBColor;
|
||||
import com.intellij.ui.components.JBCheckBox;
|
||||
import com.intellij.util.NullableConsumer;
|
||||
import com.intellij.util.ui.CenteredIcon;
|
||||
import com.jetbrains.python.PythonSdkChooserCombo;
|
||||
import com.jetbrains.python.configuration.PyConfigurableInterpreterList;
|
||||
import com.jetbrains.python.configuration.VirtualEnvProjectFilter;
|
||||
import com.jetbrains.python.newProject.PyFrameworkProjectGenerator;
|
||||
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.sdk.PythonSdkType;
|
||||
import com.jetbrains.python.sdk.flavors.JythonSdkFlavor;
|
||||
import com.jetbrains.python.sdk.flavors.PyPySdkFlavor;
|
||||
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
|
||||
import icons.PythonIcons;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
abstract public class AbstractProjectSettingsStep extends AbstractActionWithPanel implements DumbAware {
|
||||
protected final DirectoryProjectGenerator myProjectGenerator;
|
||||
private final NullableConsumer<AbstractProjectSettingsStep> myCallback;
|
||||
private PythonSdkChooserCombo mySdkCombo;
|
||||
private JCheckBox myFrameworkCheckbox;
|
||||
private boolean myInstallFrameworkChanged;
|
||||
private TextFieldWithBrowseButton myLocationField;
|
||||
protected final File myProjectDirectory;
|
||||
private Button myCreateButton;
|
||||
private JLabel myErrorLabel;
|
||||
private AnAction myCreateAction;
|
||||
|
||||
public AbstractProjectSettingsStep(DirectoryProjectGenerator projectGenerator, NullableConsumer<AbstractProjectSettingsStep> callback) {
|
||||
super();
|
||||
myProjectGenerator = projectGenerator;
|
||||
myCallback = callback;
|
||||
myProjectDirectory = FileUtil.findSequentNonexistentFile(new File(ProjectUtil.getBaseDir()), "untitled", "");
|
||||
if (myProjectGenerator instanceof WebProjectTemplate) {
|
||||
((WebProjectTemplate)myProjectGenerator).getPeer().addSettingsStateListener(new WebProjectGenerator.SettingsStateListener() {
|
||||
@Override
|
||||
public void stateChanged(boolean validSettings) {
|
||||
if (validSettings) {
|
||||
setErrorText(null);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
myCreateAction = new AnAction("Create ", "Create Project", getIcon()) {
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
boolean isOk;
|
||||
try {
|
||||
isOk = checkValid();
|
||||
if (myProjectGenerator instanceof WebProjectTemplate) {
|
||||
final ValidationInfo validationInfo = ((WebProjectTemplate)myProjectGenerator).getPeer().validate();
|
||||
isOk = validationInfo == null;
|
||||
if (!isOk) {
|
||||
setErrorText(validationInfo.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (RuntimeException e1) {
|
||||
isOk = false;
|
||||
setErrorText(e1.getMessage());
|
||||
}
|
||||
|
||||
if (isOk && myCallback != null)
|
||||
myCallback.consume(AbstractProjectSettingsStep.this);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public JPanel createPanel() {
|
||||
final JPanel mainPanel = new JPanel(new BorderLayout());
|
||||
mainPanel.setPreferredSize(new Dimension(mainPanel.getPreferredSize().width, 450));
|
||||
|
||||
final JPanel panel = createBasePanel();
|
||||
mainPanel.add(panel, BorderLayout.NORTH);
|
||||
|
||||
final JPanel advancedSettings = createAdvancedSettings();
|
||||
if (advancedSettings != null)
|
||||
mainPanel.add(advancedSettings, BorderLayout.CENTER);
|
||||
|
||||
final JPanel bottomPanel = new JPanel(new BorderLayout());
|
||||
myCreateButton = new Button(myCreateAction, myCreateAction.getTemplatePresentation());
|
||||
|
||||
bottomPanel.setPreferredSize(new Dimension(mainPanel.getPreferredSize().width, 40));
|
||||
myCreateButton.setPreferredSize(new Dimension(mainPanel.getPreferredSize().width, 40));
|
||||
myErrorLabel = new JLabel("");
|
||||
myErrorLabel.setForeground(JBColor.RED);
|
||||
bottomPanel.add(myErrorLabel, BorderLayout.WEST);
|
||||
bottomPanel.add(myCreateButton, BorderLayout.CENTER);
|
||||
mainPanel.add(bottomPanel, BorderLayout.SOUTH);
|
||||
|
||||
return mainPanel;
|
||||
}
|
||||
|
||||
protected Icon getIcon() {
|
||||
return myProjectGenerator.getIcon();
|
||||
}
|
||||
|
||||
private JPanel createBasePanel() {
|
||||
final JPanel panel = new JPanel(new GridBagLayout());
|
||||
final GridBagConstraints c = new GridBagConstraints();
|
||||
c.fill = GridBagConstraints.HORIZONTAL;
|
||||
c.anchor = GridBagConstraints.NORTHWEST;
|
||||
c.weightx = 0;
|
||||
c.insets = new Insets(2, 2, 2, 2);
|
||||
myLocationField = new TextFieldWithBrowseButton();
|
||||
myLocationField.setText(myProjectDirectory.toString());
|
||||
|
||||
final FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor();
|
||||
myLocationField.addBrowseFolderListener("Select base directory", "Select base directory for the Project",
|
||||
null, descriptor);
|
||||
|
||||
final JLabel locationLabel = new JLabel("Location:");
|
||||
c.gridx = 0;
|
||||
c.gridy = 0;
|
||||
panel.add(locationLabel, c);
|
||||
|
||||
c.gridx = 1;
|
||||
c.gridy = 0;
|
||||
c.weightx = 1.;
|
||||
panel.add(myLocationField, c);
|
||||
|
||||
final JLabel interpreterLabel = new JLabel("Interpreter:", SwingConstants.LEFT) {
|
||||
@Override
|
||||
public Dimension getMinimumSize() {
|
||||
return new JLabel("Project name:").getPreferredSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
return getMinimumSize();
|
||||
}
|
||||
};
|
||||
c.gridx = 0;
|
||||
c.gridy = 1;
|
||||
c.weightx = 0;
|
||||
panel.add(interpreterLabel, c);
|
||||
|
||||
final Project project = ProjectManager.getInstance().getDefaultProject();
|
||||
final List<Sdk> sdks = PyConfigurableInterpreterList.getInstance(project).getAllPythonSdks();
|
||||
VirtualEnvProjectFilter.removeAllAssociated(sdks);
|
||||
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;
|
||||
}
|
||||
});
|
||||
mySdkCombo.setButtonIcon(PythonIcons.Python.InterpreterGear);
|
||||
|
||||
c.gridx = 1;
|
||||
c.gridy = 1;
|
||||
c.weightx = 1.;
|
||||
panel.add(mySdkCombo, c);
|
||||
|
||||
myFrameworkCheckbox = new JBCheckBox("Install <framework>");
|
||||
c.gridx = 0;
|
||||
c.gridy = 2;
|
||||
c.gridwidth = 2;
|
||||
c.weightx = 0.0;
|
||||
panel.add(myFrameworkCheckbox, c);
|
||||
myFrameworkCheckbox.setVisible(false);
|
||||
|
||||
registerValidators();
|
||||
return panel;
|
||||
}
|
||||
|
||||
protected void registerValidators() {
|
||||
myFrameworkCheckbox.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
myInstallFrameworkChanged = true;
|
||||
checkValid();
|
||||
}
|
||||
});
|
||||
|
||||
myLocationField.getTextField().getDocument().addDocumentListener(new DocumentAdapter() {
|
||||
@Override
|
||||
protected void textChanged(DocumentEvent e) {
|
||||
checkValid();
|
||||
}
|
||||
});
|
||||
final ActionListener listener = new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
checkValid();
|
||||
}
|
||||
};
|
||||
mySdkCombo.getComboBox().addPropertyChangeListener(new PropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent event) {
|
||||
checkValid();
|
||||
}
|
||||
});
|
||||
myLocationField.getTextField().addActionListener(listener);
|
||||
mySdkCombo.getComboBox().addActionListener(listener);
|
||||
mySdkCombo.addActionListener(listener);
|
||||
}
|
||||
|
||||
public boolean checkValid() {
|
||||
final String projectName = myLocationField.getText();
|
||||
if (projectName.trim().isEmpty()) {
|
||||
setErrorText("Project name can't be empty");
|
||||
return false;
|
||||
}
|
||||
if (myLocationField.getText().indexOf('$') >= 0) {
|
||||
setErrorText("Project directory name must not contain the $ character");
|
||||
return false;
|
||||
}
|
||||
if (myProjectGenerator != null) {
|
||||
final String baseDirPath = myLocationField.getTextField().getText();
|
||||
ValidationResult validationResult = myProjectGenerator.validate(baseDirPath);
|
||||
if (!validationResult.isOk()) {
|
||||
setErrorText(validationResult.getErrorMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (myProjectGenerator instanceof WebProjectTemplate) {
|
||||
final ValidationInfo validationInfo = ((WebProjectTemplate)myProjectGenerator).getPeer().validate();
|
||||
if (validationInfo != null) {
|
||||
setErrorText(validationInfo.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final Sdk sdk = getSdk();
|
||||
setErrorText(null);
|
||||
myFrameworkCheckbox.setVisible(false);
|
||||
|
||||
final boolean isPy3k = sdk != null && PythonSdkType.getLanguageLevelForSdk(sdk).isPy3K();
|
||||
if (sdk != null && PythonSdkType.isRemote(sdk) && !acceptsRemoteSdk(myProjectGenerator)) {
|
||||
setErrorText("Please choose a local interpreter");
|
||||
return false;
|
||||
}
|
||||
else if (myProjectGenerator instanceof PyFrameworkProjectGenerator) {
|
||||
PyFrameworkProjectGenerator frameworkProjectGenerator = (PyFrameworkProjectGenerator)myProjectGenerator;
|
||||
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");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (isPy3k && !((PyFrameworkProjectGenerator)myProjectGenerator).supportsPython3()) {
|
||||
setErrorText(frameworkName + " is not supported for the selected interpreter");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (sdk == null) {
|
||||
setErrorText("No Python interpreter selected");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setErrorText(@Nullable String text) {
|
||||
myErrorLabel.setText(text);
|
||||
myCreateButton.setEnabled(text == null);
|
||||
}
|
||||
|
||||
public 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 static boolean acceptsRemoteSdk(DirectoryProjectGenerator generator) {
|
||||
if (generator instanceof PyFrameworkProjectGenerator) {
|
||||
return ((PyFrameworkProjectGenerator)generator).acceptsRemoteSdk();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isFrameworkInstalled(Sdk sdk) {
|
||||
PyFrameworkProjectGenerator projectGenerator = (PyFrameworkProjectGenerator)getProjectGenerator();
|
||||
return projectGenerator != null && projectGenerator.isFrameworkInstalled(sdk);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected JPanel createAdvancedSettings() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public DirectoryProjectGenerator getProjectGenerator() {
|
||||
return myProjectGenerator;
|
||||
}
|
||||
|
||||
private static class Button extends ActionButtonWithText {
|
||||
private static final Icon DEFAULT_ICON = PythonIcons.Python.Python;
|
||||
|
||||
public Button(AnAction action, Presentation presentation) {
|
||||
super(action,
|
||||
wrapIcon(presentation),
|
||||
"NewProject",
|
||||
new Dimension(32, 32));
|
||||
setBorder(new EmptyBorder(3, 3, 3, 3));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getToolTipText() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int horizontalTextAlignment() {
|
||||
return SwingConstants.RIGHT;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int iconTextSpace() {
|
||||
return 8;
|
||||
}
|
||||
|
||||
private static Presentation wrapIcon(Presentation presentation) {
|
||||
Icon original = presentation.getIcon();
|
||||
CenteredIcon centered = new CenteredIcon(original != null ? original : DEFAULT_ICON, 40, 40, false);
|
||||
presentation.setIcon(centered);
|
||||
return presentation;
|
||||
}
|
||||
}
|
||||
|
||||
public Sdk getSdk() {
|
||||
return (Sdk)mySdkCombo.getComboBox().getSelectedItem();
|
||||
}
|
||||
|
||||
public String getProjectLocation() {
|
||||
return myLocationField.getText();
|
||||
}
|
||||
|
||||
public boolean installFramework() {
|
||||
return myFrameworkCheckbox.isSelected() && myFrameworkCheckbox.isVisible();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2000-2013 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jetbrains.python.newProject.actions;
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.DefaultActionGroup;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.platform.DirectoryProjectGenerator;
|
||||
import com.intellij.util.NullableConsumer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ProjectSpecificAction extends DefaultActionGroup implements DumbAware {
|
||||
|
||||
private final ProjectSpecificSettingsStep mySettings;
|
||||
|
||||
public ProjectSpecificAction(@NotNull final NullableConsumer<AbstractProjectSettingsStep> callback,
|
||||
@NotNull final DirectoryProjectGenerator projectGenerator) {
|
||||
super(projectGenerator.getName(), true);
|
||||
getTemplatePresentation().setIcon(projectGenerator.getIcon());
|
||||
mySettings = new ProjectSpecificSettingsStep(projectGenerator, callback);
|
||||
add(mySettings);
|
||||
}
|
||||
|
||||
public Sdk getSdk() {
|
||||
return mySettings.getSdk();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
super.actionPerformed(e);
|
||||
mySettings.selectCompatiblePython();
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2000-2013 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jetbrains.python.newProject.actions;
|
||||
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.ui.VerticalFlowLayout;
|
||||
import com.intellij.platform.DirectoryProjectGenerator;
|
||||
import com.intellij.ui.HideableDecorator;
|
||||
import com.intellij.util.NullableConsumer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
public class ProjectSpecificSettingsStep extends AbstractProjectSettingsStep implements DumbAware {
|
||||
|
||||
public ProjectSpecificSettingsStep(@NotNull final DirectoryProjectGenerator projectGenerator,
|
||||
@NotNull final NullableConsumer<AbstractProjectSettingsStep> callback) {
|
||||
super(projectGenerator, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected JPanel createAdvancedSettings() {
|
||||
final JComponent advancedSettings = myProjectGenerator.getSettingsPanel(myProjectDirectory);
|
||||
if (advancedSettings != null) {
|
||||
final JPanel jPanel = new JPanel(new VerticalFlowLayout());
|
||||
final HideableDecorator deco = new HideableDecorator(jPanel, "Mor&e Settings", false);
|
||||
deco.setContentComponent(advancedSettings);
|
||||
return jPanel;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright 2000-2013 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jetbrains.python.newProject.actions;
|
||||
|
||||
import com.intellij.ide.GeneralSettings;
|
||||
import com.intellij.internal.statistic.UsageTrigger;
|
||||
import com.intellij.internal.statistic.beans.ConvertUsagesUtil;
|
||||
import com.intellij.openapi.actionSystem.DefaultActionGroup;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.options.ConfigurationException;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectManager;
|
||||
import com.intellij.openapi.projectRoots.ProjectJdkTable;
|
||||
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.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.platform.DirectoryProjectGenerator;
|
||||
import com.intellij.platform.PlatformProjectOpenProcessor;
|
||||
import com.intellij.projectImport.ProjectOpenedCallback;
|
||||
import com.intellij.util.NullableConsumer;
|
||||
import com.jetbrains.python.configuration.PyConfigurableInterpreterList;
|
||||
import com.jetbrains.python.newProject.PyFrameworkProjectGenerator;
|
||||
import com.jetbrains.python.newProject.PyNewProjectSettings;
|
||||
import com.jetbrains.python.newProject.PythonBaseProjectGenerator;
|
||||
import com.jetbrains.python.sdk.PyDetectedSdk;
|
||||
import com.jetbrains.python.sdk.PySdkService;
|
||||
import com.jetbrains.python.sdk.PythonSdkAdditionalData;
|
||||
import com.jetbrains.python.sdk.PythonSdkType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
public class PyCharmNewProjectStep extends DefaultActionGroup implements DumbAware {
|
||||
private static final Logger LOG = Logger.getInstance(PyCharmNewProjectStep.class);
|
||||
|
||||
public PyCharmNewProjectStep(@Nullable final Runnable runnable) {
|
||||
super("Select Project Type", true);
|
||||
|
||||
final NullableConsumer<AbstractProjectSettingsStep> callback = new NullableConsumer<AbstractProjectSettingsStep>() {
|
||||
@Override
|
||||
public void consume(@Nullable AbstractProjectSettingsStep settingsStep) {
|
||||
if (runnable != null)
|
||||
runnable.run();
|
||||
if (settingsStep == null) return;
|
||||
|
||||
Sdk sdk = settingsStep.getSdk();
|
||||
final Project project = ProjectManager.getInstance().getDefaultProject();
|
||||
final ProjectSdksModel model = PyConfigurableInterpreterList.getInstance(project).getModel();
|
||||
if (sdk instanceof PyDetectedSdk) {
|
||||
final String name = sdk.getName();
|
||||
VirtualFile sdkHome = ApplicationManager.getApplication().runWriteAction(new Computable<VirtualFile>() {
|
||||
@Override
|
||||
public VirtualFile compute() {
|
||||
return LocalFileSystem.getInstance().refreshAndFindFileByPath(name);
|
||||
}
|
||||
});
|
||||
PySdkService.getInstance().solidifySdk(sdk);
|
||||
sdk = SdkConfigurationUtil.setupSdk(ProjectJdkTable.getInstance().getAllJdks(), sdkHome, PythonSdkType.getInstance(), true, null,
|
||||
null);
|
||||
model.addSdk(sdk);
|
||||
try {
|
||||
model.apply();
|
||||
}
|
||||
catch (ConfigurationException exception) {
|
||||
LOG.error("Error adding detected python interpreter " + exception.getMessage());
|
||||
}
|
||||
}
|
||||
Project newProject = generateProject(project, settingsStep);
|
||||
if (newProject != null) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Project generateProject(@NotNull final Project project, @NotNull final AbstractProjectSettingsStep settings) {
|
||||
final DirectoryProjectGenerator generator = settings.getProjectGenerator();
|
||||
final File location = new File(settings.getProjectLocation());
|
||||
if (!location.exists() && !location.mkdirs()) {
|
||||
Messages.showErrorDialog(project, "Cannot create directory '" + location + "'", "Create Project");
|
||||
return null;
|
||||
}
|
||||
|
||||
final VirtualFile baseDir = ApplicationManager.getApplication().runWriteAction(new Computable<VirtualFile>() {
|
||||
public VirtualFile compute() {
|
||||
return LocalFileSystem.getInstance().refreshAndFindFileByIoFile(location);
|
||||
}
|
||||
});
|
||||
LOG.assertTrue(baseDir != null, "Couldn't find '" + location + "' in VFS");
|
||||
baseDir.refresh(false, true);
|
||||
|
||||
if (baseDir.getChildren().length > 0) {
|
||||
int rc = Messages.showYesNoDialog(project,
|
||||
"The directory '" + location +
|
||||
"' is not empty. Would you like to create a project from existing sources instead?",
|
||||
"Create New Project", Messages.getQuestionIcon());
|
||||
if (rc == Messages.YES) {
|
||||
return PlatformProjectOpenProcessor.getInstance().doOpenProject(baseDir, null, false);
|
||||
}
|
||||
}
|
||||
|
||||
String generatorName = generator == null ? "empty" : ConvertUsagesUtil.ensureProperKey(generator.getName());
|
||||
UsageTrigger.trigger("NewDirectoryProjectAction." + generatorName);
|
||||
|
||||
GeneralSettings.getInstance().setLastProjectCreationLocation(location.getParent());
|
||||
|
||||
return PlatformProjectOpenProcessor.doOpenProject(baseDir, null, false, -1, new ProjectOpenedCallback() {
|
||||
@Override
|
||||
public void projectOpened(Project project, Module module) {
|
||||
if (generator != null) {
|
||||
final Object projectSettings = generator.getProjectSettings();
|
||||
if (projectSettings instanceof PyNewProjectSettings) {
|
||||
((PyNewProjectSettings)projectSettings).setSdk(settings.getSdk());
|
||||
((PyNewProjectSettings)projectSettings).setInstallFramework(settings.installFramework());
|
||||
}
|
||||
//noinspection unchecked
|
||||
generator.generateProject(project, baseDir, projectSettings, module);
|
||||
}
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
};
|
||||
|
||||
final ProjectSpecificAction action = new ProjectSpecificAction(callback, new PythonBaseProjectGenerator());
|
||||
add(action);
|
||||
|
||||
final DirectoryProjectGenerator[] generators = Extensions.getExtensions(DirectoryProjectGenerator.EP_NAME);
|
||||
Arrays.sort(generators, new Comparator<DirectoryProjectGenerator>() {
|
||||
@Override
|
||||
public int compare(DirectoryProjectGenerator o1, DirectoryProjectGenerator 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());
|
||||
}
|
||||
});
|
||||
for (DirectoryProjectGenerator generator : generators) {
|
||||
add(new ProjectSpecificAction(callback, generator));
|
||||
}
|
||||
}
|
||||
|
||||
public PyCharmNewProjectStep() {
|
||||
this(null);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package com.jetbrains.python.newProject;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.platform.DirectoryProjectGenerator;
|
||||
|
||||
@@ -25,7 +24,7 @@ import com.intellij.platform.DirectoryProjectGenerator;
|
||||
public interface PyFrameworkProjectGenerator<T> extends DirectoryProjectGenerator<T> {
|
||||
String getFrameworkTitle();
|
||||
|
||||
boolean isFrameworkInstalled(Project project, Sdk sdk);
|
||||
boolean isFrameworkInstalled(Sdk sdk);
|
||||
|
||||
boolean acceptsRemoteSdk();
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
|
||||
<actions>
|
||||
<group id="PlatformOpenProjectGroup">
|
||||
<action id="NewDirectoryProject" class="com.jetbrains.python.newProject.PythonNewDirectoryProjectAction"/>
|
||||
<action id="NewDirectoryProject" class="com.jetbrains.python.newProject.PyCharmNewProjectAction"/>
|
||||
<add-to-group group-id="FileOpenGroup" anchor="first"/>
|
||||
</group>
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
icon="AllIcons.RunConfigurations.RerunFailedTests"/>
|
||||
|
||||
<group id="WelcomeScreen.Platform.NewProject">
|
||||
<action id="WelcomeScreen.CreateDirectoryProject" class="com.jetbrains.python.newProject.PythonNewDirectoryProjectAction" icon="AllIcons.General.CreateNewProject"/>
|
||||
<action id="WelcomeScreen.CreateDirectoryProject" class="com.jetbrains.python.newProject.actions.PyCharmNewProjectStep" icon="AllIcons.General.CreateNewProject"/>
|
||||
<action id="WelcomeScreen.OpenDirectoryProject" class="com.intellij.ide.actions.OpenFileAction" icon="AllIcons.General.OpenProject"/>
|
||||
|
||||
<add-to-group group-id="WelcomeScreen.QuickStart" anchor="first"/>
|
||||
|
||||
Reference in New Issue
Block a user