/* * Copyright 2000-2010 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 org.jetbrains.plugins.github.ui; import com.intellij.ide.BrowserUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.ui.ComboBox; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.DocumentAdapter; import com.intellij.ui.HyperlinkAdapter; import com.intellij.ui.components.JBLabel; import com.intellij.util.ThrowableConvertor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.github.api.GithubApiUtil; import org.jetbrains.plugins.github.api.GithubUser; import org.jetbrains.plugins.github.exceptions.GithubAuthenticationException; import org.jetbrains.plugins.github.exceptions.GithubOperationCanceledException; import org.jetbrains.plugins.github.util.*; import javax.swing.*; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.event.HyperlinkEvent; import javax.swing.text.Document; import javax.swing.text.PlainDocument; import java.awt.*; import java.awt.event.*; import java.io.IOException; /** * @author oleg * @date 10/20/10 */ public class GithubSettingsPanel { private static final String DEFAULT_PASSWORD_TEXT = "************"; private final static String AUTH_PASSWORD = "Password"; private final static String AUTH_TOKEN = "Token"; private static final Logger LOG = GithubUtil.LOG; private final GithubSettings mySettings; private JTextField myLoginTextField; private JPasswordField myPasswordField; private JPasswordField myTokenField; // look at createUIComponents() to understand private JTextPane mySignupTextField; private JPanel myPane; private JButton myTestButton; private JTextField myHostTextField; private ComboBox myAuthTypeComboBox; private JPanel myCardPanel; private JBLabel myAuthTypeLabel; private JSpinner myTimeoutSpinner; private JButton myCreateTokenButton; private boolean myCredentialsModified; public GithubSettingsPanel() { mySettings = GithubSettings.getInstance(); mySignupTextField.addHyperlinkListener(new HyperlinkAdapter() { @Override protected void hyperlinkActivated(final HyperlinkEvent e) { BrowserUtil.browse(e.getURL()); } }); mySignupTextField.setText("Do not have an account at github.com? " + "Sign up" + ""); mySignupTextField.setBackground(myPane.getBackground()); mySignupTextField.setCursor(new Cursor(Cursor.HAND_CURSOR)); myAuthTypeLabel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0)); myAuthTypeComboBox.addItem(AUTH_PASSWORD); myAuthTypeComboBox.addItem(AUTH_TOKEN); final Project project = ProjectManager.getInstance().getDefaultProject(); myTestButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { try { final GithubAuthData auth = getAuthData(); GithubUser user = GithubUtil .computeValueInModal(project, "Access to GitHub", new ThrowableConvertor() { @NotNull @Override public GithubUser convert(ProgressIndicator indicator) throws IOException { return GithubUtil.checkAuthData(project, new GithubAuthDataHolder(auth), indicator); } }); if (GithubAuthData.AuthType.TOKEN.equals(getAuthType())) { GithubNotifications.showInfoDialog(myPane, "Success", "Connection successful for user " + user.getLogin()); } else { GithubNotifications.showInfoDialog(myPane, "Success", "Connection successful"); } } catch (GithubAuthenticationException ex) { GithubNotifications.showErrorDialog(myPane, "Login Failure", "Can't login using given credentials: " + ex.getMessage()); } catch (IOException ex) { LOG.info(ex); GithubNotifications.showErrorDialog(myPane, "Login Failure", "Can't login: " + GithubUtil.getErrorTextFromException(ex)); } } }); myCreateTokenButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { try { myPasswordField.setText( GithubUtil.computeValueInModal(project, "Access to GitHub", new ThrowableConvertor() { @NotNull @Override public String convert(ProgressIndicator indicator) throws IOException { return GithubUtil.runTaskWithBasicAuthForHost(project, GithubAuthDataHolder.createFromSettings(indicator.getModalityState()), indicator, getHost(), new ThrowableConvertor() { @NotNull @Override public String convert(@NotNull GithubAuthData auth) throws IOException { return GithubApiUtil.getMasterToken(auth, "IntelliJ plugin"); } } ); } }) ); } catch (IOException ex) { GithubNotifications.showErrorDialog(myPane, "Can't create API token", ex); } } }); myPasswordField.getDocument().addDocumentListener(new DocumentAdapter() { @Override protected void textChanged(DocumentEvent e) { myCredentialsModified = true; } }); DocumentListener passwordEraser = new DocumentAdapter() { @Override protected void textChanged(DocumentEvent e) { if (!myCredentialsModified) { erasePassword(); } } }; myHostTextField.getDocument().addDocumentListener(passwordEraser); myLoginTextField.getDocument().addDocumentListener(passwordEraser); myPasswordField.addFocusListener(new FocusListener() { @Override public void focusGained(FocusEvent e) { if (!myCredentialsModified && !getPassword().isEmpty()) { erasePassword(); } } @Override public void focusLost(FocusEvent e) { } }); myAuthTypeComboBox.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { if (e.getStateChange() == ItemEvent.SELECTED) { String item = e.getItem().toString(); if (AUTH_PASSWORD.equals(item)) { ((CardLayout)myCardPanel.getLayout()).show(myCardPanel, AUTH_PASSWORD); } else if (AUTH_TOKEN.equals(item)) { ((CardLayout)myCardPanel.getLayout()).show(myCardPanel, AUTH_TOKEN); } erasePassword(); } } }); reset(); } private void erasePassword() { setPassword(""); myCredentialsModified = true; } public JComponent getPanel() { return myPane; } @NotNull public String getHost() { return myHostTextField.getText().trim(); } @NotNull public String getLogin() { return myLoginTextField.getText().trim(); } public void setHost(@NotNull final String host) { myHostTextField.setText(host); } public void setLogin(@Nullable final String login) { myLoginTextField.setText(login); } @NotNull private String getPassword() { return String.valueOf(myPasswordField.getPassword()); } private void setPassword(@NotNull final String password) { // Show password as blank if password is empty myPasswordField.setText(StringUtil.isEmpty(password) ? null : password); } @NotNull public GithubAuthData.AuthType getAuthType() { Object selected = myAuthTypeComboBox.getSelectedItem(); if (AUTH_PASSWORD.equals(selected)) return GithubAuthData.AuthType.BASIC; if (AUTH_TOKEN.equals(selected)) return GithubAuthData.AuthType.TOKEN; LOG.error("GithubSettingsPanel: illegal selection: basic AuthType returned", selected.toString()); return GithubAuthData.AuthType.BASIC; } public void setAuthType(@NotNull final GithubAuthData.AuthType type) { switch (type) { case BASIC: myAuthTypeComboBox.setSelectedItem(AUTH_PASSWORD); break; case TOKEN: myAuthTypeComboBox.setSelectedItem(AUTH_TOKEN); break; case ANONYMOUS: default: myAuthTypeComboBox.setSelectedItem(AUTH_PASSWORD); } } @NotNull public GithubAuthData getAuthData() { if (!myCredentialsModified) { return mySettings.getAuthData(null); } Object selected = myAuthTypeComboBox.getSelectedItem(); if (AUTH_PASSWORD.equals(selected)) return GithubAuthData.createBasicAuth(getHost(), getLogin(), getPassword()); if (AUTH_TOKEN.equals(selected)) return GithubAuthData.createTokenAuth(getHost(), getPassword()); LOG.error("GithubSettingsPanel: illegal selection: anonymous AuthData created", selected.toString()); return GithubAuthData.createAnonymous(getHost()); } public void setConnectionTimeout(int timeout) { myTimeoutSpinner.setValue(Integer.valueOf(timeout)); } public int getConnectionTimeout() { return ((SpinnerNumberModel)myTimeoutSpinner.getModel()).getNumber().intValue(); } public void reset() { setHost(mySettings.getHost()); setLogin(mySettings.getLogin()); setPassword(mySettings.isAuthConfigured() ? DEFAULT_PASSWORD_TEXT : ""); setAuthType(mySettings.getAuthType()); setConnectionTimeout(mySettings.getConnectionTimeout()); resetCredentialsModification(); } public void apply() { if (myCredentialsModified) { mySettings.setAuthData(getAuthData(), true, null); } mySettings.setConnectionTimeout(getConnectionTimeout()); resetCredentialsModification(); } public boolean isModified() { return myCredentialsModified || !Comparing.equal(mySettings.getHost(), getHost()) || !Comparing.equal(mySettings.getConnectionTimeout(), getConnectionTimeout()); } public void resetCredentialsModification() { myCredentialsModified = false; } private void createUIComponents() { Document doc = new PlainDocument(); myPasswordField = new JPasswordField(doc, null, 0); myTokenField = new JPasswordField(doc, null, 0); myTimeoutSpinner = new JSpinner(new SpinnerNumberModel(Integer.valueOf(5000), Integer.valueOf(0), Integer.valueOf(60000), Integer.valueOf(500))); } }