package com.atsebak.embeddedlinuxjvm.ui; import com.atsebak.embeddedlinuxjvm.localization.EmbeddedLinuxJVMBundle; import com.atsebak.embeddedlinuxjvm.protocol.ssh.SSHConnectionValidator; import com.atsebak.embeddedlinuxjvm.runner.conf.EmbeddedLinuxJVMRunConfiguration; import com.atsebak.embeddedlinuxjvm.runner.data.EmbeddedLinuxJVMRunConfigurationRunnerParameters; import com.intellij.execution.JavaExecutionUtil; import com.intellij.execution.configurations.ConfigurationUtil; import com.intellij.execution.ui.ClassBrowser; import com.intellij.execution.ui.ConfigurationModuleSelector; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.options.SettingsEditor; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.LabeledComponent; import com.intellij.psi.JavaCodeFragment; import com.intellij.psi.PsiClass; import com.intellij.psi.util.PsiMethodUtil; import com.intellij.ui.EditorTextFieldWithBrowseButton; import com.intellij.ui.PanelWithAnchor; import com.intellij.ui.RawCommandLineEditor; import com.intellij.util.ui.UIUtil; import org.jdesktop.swingx.prompt.PromptSupport; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.text.AbstractDocument; import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; import javax.swing.text.DocumentFilter; import java.awt.*; import java.io.File; import java.util.regex.Matcher; import java.util.regex.Pattern; public class RunConfigurationEditor extends SettingsEditor<EmbeddedLinuxJVMRunConfiguration> implements PanelWithAnchor { private final ConfigurationModuleSelector myModuleSelector; private final Project myProject; private LabeledComponent<EditorTextFieldWithBrowseButton> myMainClass; private LabeledComponent<JComboBox> myModule; private JPanel myGenericPanel; private JCheckBox runAsRootCheckBox; private JTextField debugPort; private JTextField hostName; private JPanel mainPanel; private JTextField username; private JPasswordField password; private JButton validateConnection; private RawCommandLineEditor vmParameters; private RawCommandLineEditor programArguments; private JLabel sshStatus; private JCheckBox usingKey; private JTextField keyfile; private JButton selectPrivateKeyButton; private JTextField sshPort; private JComponent myAnchor; /** * Constructor for run configuration form * * @param project */ public RunConfigurationEditor(final Project project) { myProject = project; validateConnection.addActionListener(e -> ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() { public void run() { final ProgressIndicator progressIndicator = ProgressManager.getInstance().getProgressIndicator(); if (progressIndicator != null) { progressIndicator.setText(EmbeddedLinuxJVMBundle.getString("ssh.tryingtoconnect")); progressIndicator.setIndeterminate(true); } SSHConnectionValidator.SSHConnectionState validator = SSHConnectionValidator .builder() .port(Integer.valueOf(sshPort.getText())) .ip(hostName.getText()) .password(new String(password.getPassword())) .username(username.getText()) .useKey(usingKey.isSelected()) .key(keyfile.getText()) .build().checkSSHConnection(); sshStatus.setVisible(true); if (validator.isConnected()) { sshStatus.setText(EmbeddedLinuxJVMBundle.getString("ssh.connection.success")); sshStatus.setForeground(Color.GREEN); } else { sshStatus.setText(EmbeddedLinuxJVMBundle.getString("ssh.remote.error") + ": " + validator.getMessage()); sshStatus.setForeground(Color.RED); } } }, EmbeddedLinuxJVMBundle.getString("pi.validatingconnection"), true, myProject)); keyFileStateChange(); myModuleSelector = new ConfigurationModuleSelector(project, myModule.getComponent()); myModule.getComponent().addActionListener(e -> { }); final JFileChooser keyChooser = new JFileChooser(); keyChooser.setDialogTitle(EmbeddedLinuxJVMBundle.getString("ssh.dialog.title")); keyChooser.setMultiSelectionEnabled(false); keyChooser.setFileHidingEnabled(false); selectPrivateKeyButton.addActionListener(e -> { JButton button = (JButton) e.getSource(); if (selectPrivateKeyButton == button) { int returnVal = keyChooser.showOpenDialog(myGenericPanel); if (returnVal == JFileChooser.APPROVE_OPTION) { File file = keyChooser.getSelectedFile(); keyfile.setText(file.getAbsolutePath()); } } }); usingKey.addItemListener(e -> { JCheckBox source = (JCheckBox) e.getSource(); if (usingKey == source) { keyFileStateChange(); } }); PromptSupport.setPrompt(EmbeddedLinuxJVMBundle.getString("debugport.placeholder"), debugPort); PromptSupport.setPrompt(EmbeddedLinuxJVMBundle.getString("ssh.privatekey.ph"), keyfile); ClassBrowser.createApplicationClassBrowser(project, myModuleSelector).setField(getMainClassField()); myAnchor = UIUtil.mergeComponentsWithAnchor(myMainClass, myModule); //restrict only numbers ((AbstractDocument) sshPort.getDocument()).setDocumentFilter(new DocumentFilter() { Pattern regEx = Pattern.compile("\\d+"); @Override public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException { Matcher matcher = regEx.matcher(text); if (!matcher.matches()) { return; } super.replace(fb, offset, length, text, attrs); } }); ((AbstractDocument) debugPort.getDocument()).setDocumentFilter(new DocumentFilter() { Pattern regEx = Pattern.compile("\\d+"); @Override public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException { Matcher matcher = regEx.matcher(text); if (!matcher.matches()) { return; } super.replace(fb, offset, length, text, attrs); } }); } @Override protected void disposeEditor() { super.disposeEditor(); } private void keyFileStateChange() { if (!usingKey.isSelected()) { keyfile.setEnabled(false); password.setEnabled(true); selectPrivateKeyButton.setEnabled(false); } else { keyfile.setEnabled(false); password.setEnabled(false); selectPrivateKeyButton.setEnabled(true); } } /** * Called when application loaded/ when cancelling the settings * @param configuration */ @Override protected void resetEditorFrom(EmbeddedLinuxJVMRunConfiguration configuration) { getMainClassField().setText(configuration.getRunnerParameters().getMainclass() != null ? configuration.getRunnerParameters().getMainclass().replaceAll("\\$", "\\.") : ""); EmbeddedLinuxJVMRunConfigurationRunnerParameters parameters = configuration.getRunnerParameters(); vmParameters.setDialogCaption(EmbeddedLinuxJVMBundle.getString("app.vmoptions")); vmParameters.setText(parameters.getVmParameters()); programArguments.setDialogCaption(EmbeddedLinuxJVMBundle.getString("app.programargs")); programArguments.setText(parameters.getProgramArguments()); hostName.setText(parameters.getHostname()); runAsRootCheckBox.setSelected(parameters.isRunAsRoot()); usingKey.setSelected(parameters.isUsingKey()); keyfile.setText(parameters.getKeyPath()); debugPort.setText(parameters.getPort()); username.setText(parameters.getUsername()); password.setText(parameters.getPassword()); sshPort.setText(Integer.toString(parameters.getSshPort())); sshStatus.setVisible(false); keyFileStateChange(); } /** * When you click the apply button * @param configuration * @throws ConfigurationException */ @Override protected void applyEditorTo(EmbeddedLinuxJVMRunConfiguration configuration) throws ConfigurationException { final String className = getMainClassField().getText(); final PsiClass aClass = myModuleSelector.findClass(className); configuration.getRunnerParameters().setMainclass(aClass != null ? JavaExecutionUtil.getRuntimeQualifiedName(aClass) : className); setSettings(configuration.getRunnerParameters()); } /** * Specific settings for this runner * @param parameters */ private void setSettings(EmbeddedLinuxJVMRunConfigurationRunnerParameters parameters) { parameters.setHostname(hostName.getText()); parameters.setPort(debugPort.getText()); parameters.setRunAsRoot(runAsRootCheckBox.isSelected()); parameters.setUsername(username.getText()); parameters.setPassword(new String(password.getPassword())); parameters.setVmParameters(vmParameters.getText()); parameters.setProgramArguments(programArguments.getText()); parameters.setUsingKey(usingKey.isSelected()); parameters.setKeyPath(keyfile.getText()); if(org.apache.commons.lang.StringUtils.isEmpty(sshPort.getText())) { sshPort.setText("22"); } parameters.setSshPort(Integer.parseInt(sshPort.getText())); } /** * Returns the layout * @return */ @NotNull @Override protected JComponent createEditor() { return mainPanel; } /** * Creates UI Components */ private void createUIComponents() { myMainClass = new LabeledComponent<>(); myMainClass.setComponent(new EditorTextFieldWithBrowseButton(myProject, true, (declaration, place) -> { if (declaration instanceof PsiClass) { final PsiClass aClass = (PsiClass)declaration; if (ConfigurationUtil.MAIN_CLASS.value(aClass) && PsiMethodUtil.findMainMethod(aClass) != null || place.getParent() != null && myModuleSelector.findClass(((PsiClass)declaration).getQualifiedName()) != null) { return JavaCodeFragment.VisibilityChecker.Visibility.VISIBLE; } } return JavaCodeFragment.VisibilityChecker.Visibility.NOT_VISIBLE; })); } /** * Gets the main class to execute java app against * @return */ public EditorTextFieldWithBrowseButton getMainClassField() { return myMainClass.getComponent(); } /** * Anchor getter * @return */ @Override public JComponent getAnchor() { return myAnchor; } /** * Anchor setter * @param anchor */ @Override public void setAnchor(@Nullable JComponent anchor) { this.myAnchor = anchor; myMainClass.setAnchor(anchor); myModule.setAnchor(anchor); } }