package com.intellij.lang.javascript.flex.projectStructure.ui; import com.intellij.flex.FlexCommonUtils; import com.intellij.flex.build.AirDescriptorOptions; import com.intellij.javascript.flex.FlexApplicationComponent; import com.intellij.lang.javascript.flex.FlexBundle; import com.intellij.lang.javascript.flex.FlexUtils; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.ui.ValidationInfo; import com.intellij.openapi.util.NullableComputable; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.components.JBTabbedPane; import com.intellij.util.ArrayUtil; import com.intellij.util.PathUtil; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; import java.util.Arrays; import java.util.regex.Pattern; import static com.intellij.flex.build.AirDescriptorOptions.*; public class CreateAirDescriptorTemplateDialog extends DialogWrapper { public static final Pattern VERSION_PATTERN = Pattern.compile("[0-9]{1,3}(\\.[0-9]{1,3}){0,2}"); private JPanel myMainPanel; private JTextField myDescriptorFileNameTextField; private TextFieldWithBrowseButton myDescriptorFolderTextWithBrowse; private JComboBox myAirVersionCombo; private JTextField myAppIdTextField; private JTextField myAppNameTextField; private JTextField myAppVersionTextField; private JPanel myMobileOptionsPanel; private JCheckBox myAndroidCheckBox; private JCheckBox myIOSCheckBox; private JCheckBox myAutoOrientCheckBox; private JCheckBox myFullScreenCheckBox; private JBTabbedPane myMobilePlatformsTabs; private JPanel myAndroidPanel; private JCheckBox myAndroidInternetCheckBox; private JCheckBox myAndroidWriteExternalStorageCheckBox; private JCheckBox myAndroidAccessFineLocationCheckBox; private JCheckBox myAndroidCameraCheckBox; private JPanel myIOSPanel; private JRadioButton myIOSAllRadioButton; private JRadioButton myIPhoneRadioButton; private JRadioButton myIPadRadioButton; private JCheckBox myIOSHighResolutionCheckBox; static final String TITLE = FlexBundle.message("create.air.descriptor.template.title"); private final Project myProject; private final String[] myExtensions; public CreateAirDescriptorTemplateDialog(final Project project, final String folderPath, final String mainClass, final String airVersion, final String[] extensions, final boolean androidEnabled, final boolean iosEnabled) { super(project); myProject = project; myExtensions = extensions; setTitle(TITLE); setOKButtonText("Create"); initControls(); init(); final String appName = StringUtil.getShortName(mainClass); myDescriptorFileNameTextField.setText(appName + "-app.xml"); myDescriptorFolderTextWithBrowse.setText(FileUtil.toSystemDependentName(folderPath)); myAirVersionCombo.setSelectedItem(airVersion); myAppIdTextField.setText(mainClass); myAppNameTextField.setText(appName); myAppVersionTextField.setText("0.0.0"); myAndroidCheckBox.setSelected(androidEnabled); UIUtil.applyStyle(UIUtil.ComponentStyle.MINI, myAndroidInternetCheckBox); UIUtil.applyStyle(UIUtil.ComponentStyle.MINI, myAndroidWriteExternalStorageCheckBox); UIUtil.applyStyle(UIUtil.ComponentStyle.MINI, myAndroidAccessFineLocationCheckBox); UIUtil.applyStyle(UIUtil.ComponentStyle.MINI, myAndroidCameraCheckBox); myAndroidInternetCheckBox.setSelected(true); myAndroidWriteExternalStorageCheckBox.setSelected(false); myAndroidAccessFineLocationCheckBox.setSelected(false); myAndroidCameraCheckBox.setSelected(false); myIOSCheckBox.setSelected(iosEnabled); myIOSAllRadioButton.setSelected(true); myMobileOptionsPanel.setVisible(androidEnabled || iosEnabled); updateControls(); } private void initControls() { myDescriptorFolderTextWithBrowse .addBrowseFolderListener(null, null, myProject, FileChooserDescriptorFactory.createSingleFolderDescriptor()); final String[] items = Arrays.copyOfRange(ArrayUtil.reverseArray(FlexApplicationComponent.AIR_VERSIONS), 0, 8); myAirVersionCombo.setModel(new DefaultComboBoxModel(items)); final ActionListener listener = new ActionListener() { public void actionPerformed(final ActionEvent e) { updateControls(); } }; myAndroidCheckBox.addActionListener(listener); myIOSCheckBox.addActionListener(listener); } protected JComponent createCenterPanel() { return myMainPanel; } protected ValidationInfo doValidate() { final String fileName = myDescriptorFileNameTextField.getText().trim(); if (fileName.isEmpty()) { return new ValidationInfo("Descriptor file name not set", myDescriptorFileNameTextField); } if (!fileName.toLowerCase().endsWith(".xml")) { return new ValidationInfo("Descriptor file name must have xml extension", myDescriptorFileNameTextField); } final String folderPath = myDescriptorFolderTextWithBrowse.getText().trim(); if (folderPath.isEmpty()) { return new ValidationInfo("Folder is not set", myDescriptorFolderTextWithBrowse); } final VirtualFile dir = LocalFileSystem.getInstance().findFileByPath(folderPath); if (dir != null && !dir.isDirectory()) { return new ValidationInfo("Folder for AIR descriptor must be specified", myDescriptorFolderTextWithBrowse); } final String airVersion = ((String)myAirVersionCombo.getSelectedItem()).trim(); if (airVersion.isEmpty()) { return new ValidationInfo("AIR version is not set", myAirVersionCombo); } if (!VERSION_PATTERN.matcher(airVersion).matches()) { return new ValidationInfo("Incorrect AIR version", myAirVersionCombo); } final String appId = myAppIdTextField.getText().trim(); if (appId.isEmpty()) { return new ValidationInfo("Application ID is required", myAppIdTextField); } if (!appId.equals(FlexCommonUtils.fixApplicationId(appId))) { return new ValidationInfo("Application ID must contain only following symbols: 0-9, a-z, A-Z, '.', '-'", myAppIdTextField); } if (myAppNameTextField.getText().trim().isEmpty()) { return new ValidationInfo("Application name is required", myAppNameTextField); } final String appVersion = myAppVersionTextField.getText().trim(); if (appVersion.isEmpty()) { return new ValidationInfo("Application version is not set", myAppVersionTextField); } if (StringUtil.compareVersionNumbers(airVersion, "2.5") >= 0) { if (!VERSION_PATTERN.matcher(appVersion).matches()) { return new ValidationInfo("Application version must have following format: [0-999].[0-999].[0-999]", myAppVersionTextField); } } return null; } private void updateControls() { UIUtil.setEnabled(myMobilePlatformsTabs.getTabComponentAt(0), myAndroidCheckBox.isSelected(), true); UIUtil.setEnabled(myAndroidPanel, myAndroidCheckBox.isSelected(), true); UIUtil.setEnabled(myMobilePlatformsTabs.getTabComponentAt(1), myIOSCheckBox.isSelected(), true); UIUtil.setEnabled(myIOSPanel, myIOSCheckBox.isSelected(), true); } protected void doOKAction() { final String airVersion = ((String)myAirVersionCombo.getSelectedItem()).trim(); final String appId = myAppIdTextField.getText().trim(); final String appName = myAppNameTextField.getText().trim(); final String appVersion = myAppVersionTextField.getText().trim(); final String swfName = "SWF file name is set automatically at compile time"; final boolean mobile = myMobileOptionsPanel.isVisible(); final boolean autoOrients = mobile && myAutoOrientCheckBox.isSelected(); final boolean fullScreen = mobile && myFullScreenCheckBox.isSelected(); final boolean android = mobile && myAndroidCheckBox.isSelected(); final int androidPermissions = !mobile || !android ? 0 : (myAndroidInternetCheckBox.isSelected() ? ANDROID_PERMISSION_INTERNET : 0) | (myAndroidWriteExternalStorageCheckBox.isSelected() ? ANDROID_PERMISSION_WRITE_EXTERNAL_STORAGE : 0) | (myAndroidAccessFineLocationCheckBox.isSelected() ? ANDROID_PERMISSION_ACCESS_FINE_LOCATION : 0) | (myAndroidCameraCheckBox.isSelected() ? ANDROID_PERMISSION_CAMERA : 0); final boolean ios = mobile && myIOSCheckBox.isSelected(); final boolean iPhone = mobile && ios && (myIOSAllRadioButton.isSelected() || myIPhoneRadioButton.isSelected()); final boolean iPad = mobile && ios && (myIOSAllRadioButton.isSelected() || myIPadRadioButton.isSelected()); final boolean iosHighResolution = mobile && ios && myIOSHighResolutionCheckBox.isSelected(); final AirDescriptorOptions options = new AirDescriptorOptions(airVersion, appId, appName, appVersion, swfName, myExtensions, mobile, autoOrients, fullScreen, android, androidPermissions, ios, iPhone, iPad, iosHighResolution); if (createAirDescriptorTemplate(myProject, true, getDescriptorPath(), options) != null) { super.doOKAction(); } } @Nullable private static VirtualFile createAirDescriptorTemplate(final Project project, final boolean interactive, final String descriptorPath, final AirDescriptorOptions options) { final VirtualFile dir = FlexUtils.createDirIfMissing(project, interactive, PathUtil.getParentPath(descriptorPath), TITLE); if (dir == null) return null; final String fileName = PathUtil.getFileName(descriptorPath); final VirtualFile file = dir.findChild(fileName); if (file != null) { if (file.isDirectory()) { if (interactive) { Messages.showErrorDialog(project, "Can't create AIR descriptor file.\nFolder with such name exists.", TITLE); } return null; } final int choice = interactive ? Messages.showYesNoDialog(project, FlexBundle.message("file.exists.replace.question", fileName), TITLE, Messages.getQuestionIcon()) : Messages.YES; if (choice != Messages.YES) { return null; } } try { final Ref<VirtualFile> fileRef = new Ref<>(); final IOException exception = ApplicationManager.getApplication().runWriteAction((NullableComputable<IOException>)() -> { try { fileRef.set(FlexUtils.addFileWithContent(fileName, options.getAirDescriptorText(), dir)); } catch (IOException e) { return e; } return null; }); if (exception != null) { throw exception; } return fileRef.get(); } catch (IOException e) { if (interactive) { Messages.showErrorDialog(project, "Failed to create AIR descriptor file: " + e.getMessage(), TITLE); } return null; } } public String getDescriptorPath() { return FileUtil.toSystemIndependentName(myDescriptorFolderTextWithBrowse.getText().trim() + "/" + myDescriptorFileNameTextField.getText().trim()); } public boolean isBothAndroidAndIosSelected() { return myAndroidCheckBox.isVisible() && myAndroidCheckBox.isSelected() && myIOSCheckBox.isVisible() && myIOSCheckBox.isSelected(); } protected String getHelpId() { return "flex.CreateAirDescriptorTemplateDialog"; } }