blob: 3b83ae80205f76489adfe3ce0e21e08e440352c2 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.netbeans.modules.selenium2.webclient.protractor;
import java.awt.EventQueue;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.filechooser.FileNameExtensionFilter;
import org.netbeans.api.project.Project;
import org.netbeans.modules.selenium2.webclient.protractor.preferences.ProtractorPreferences;
import org.netbeans.modules.selenium2.webclient.protractor.preferences.ProtractorPreferencesValidator;
import org.netbeans.modules.web.common.api.ValidationResult;
import org.openide.filesystems.FileChooserBuilder;
import org.openide.filesystems.FileUtil;
import org.openide.util.ChangeSupport;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
/**
*
* @author Theofanis Oikonomou
*/
public class CustomizerProtractor extends javax.swing.JPanel {
private final Project project;
private final ChangeSupport changeSupport = new ChangeSupport(this);
private boolean autoDiscovered = false;
private volatile String protractor;
private volatile String userConfigurationFile;
// @GuardedBy("EDT")
private ValidationResult validationResult;
public CustomizerProtractor(Project project) {
assert EventQueue.isDispatchThread();
assert project != null;
this.project = project;
initComponents();
init();
}
public void addChangeListener(ChangeListener listener) {
changeSupport.addChangeListener(listener);
}
public void removeChangeListener(ChangeListener listener) {
changeSupport.removeChangeListener(listener);
}
public String getProtractor() {
return protractor;
}
public String getUserConfigurationFile() {
return userConfigurationFile;
}
public String getWarningMessage() {
assert EventQueue.isDispatchThread();
for (ValidationResult.Message message : validationResult.getWarnings()) {
return message.getMessage();
}
return null;
}
public String getErrorMessage() {
assert EventQueue.isDispatchThread();
for (ValidationResult.Message message : validationResult.getErrors()) {
return message.getMessage();
}
return null;
}
@NbBundle.Messages({"CustomizerProtractor.protractor.dir.info=Full path of protractor (typically node_modules/protractor/bin/protractor).",
"CustomizerProtractor.user.configuration.file.info=Full path to configuration file."})
private void init() {
assert EventQueue.isDispatchThread();
// get saved protractor executable if previously set from protractor preferences
String protractorExec = ProtractorPreferences.getProtractor(project);
if(protractorExec == null) {
// not set yet, so search for it in user's PATH
String userPath = System.getenv("PATH"); // NOI18N
if(userPath != null) {
List<String> paths = Arrays.asList(userPath.split(File.pathSeparator));
final String execName = "protractor"; // NOI18N
for (String path : paths) {
File file = new File(path);
if (file.isFile()) {
if (path.endsWith(execName)) {
if (isProtractorExecValid(path)) { // protractor executable is globally installed and in user's PATH
try {
protractorExec = file.getCanonicalPath();
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
break;
}
}
} else {
String[] list = file.list(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(execName);
}
});
if(list != null && list.length == 1) { // protractor executable is globally installed and the containing directory is in user's PATH
autoDiscovered = true;
if(Utilities.isWindows()) {
// if C:\Users\name\AppData\Roaming\npm is in PATH
// C:\Users\name\AppData\Roaming\npm\protractor(.cmd) are available
// but both actually call C:\Users\name\AppData\Roaming\npm\node_modules\protractor\bin\protractor
protractorExec = new File(path, "node_modules/protractor/bin/protractor").getAbsolutePath();
} else {
protractorExec = path.endsWith(File.separator) ? path + execName : path + File.separator + execName;
File f = new File(protractorExec);
try {
protractorExec = f.getCanonicalPath();
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
}
break;
}
}
}
}
}
if(protractorExec == null) {
// not found in user's PATH, so search for it in project's local node_modules dir
String exec = new File(FileUtil.toFile(project.getProjectDirectory()), "node_modules/protractor/bin/protractor").getAbsolutePath();
if(isProtractorExecValid(exec)) { // protractor executable is installed in project's local node_modules dir
protractorExec = exec;
}
}
protractorDirTextField.setText(protractorExec);
protractorDirInfoLabel.setText(Bundle.CustomizerProtractor_protractor_dir_info());
// get saved user configuration file if previously set from protractor preferences
String configFile = ProtractorPreferences.getUserConfigurationFile(project);
userConfigurationFileTextField.setText(configFile);
userConfigurationFileInfoLabel.setText(Bundle.CustomizerProtractor_user_configuration_file_info());
// listeners
addListeners();
// initial validation
validateData();
}
private boolean isProtractorExecValid(String path) {
ValidationResult result = new ProtractorPreferencesValidator()
.validateProtractor(path)
.getResult();
if (result.isFaultless()) {
autoDiscovered = true;
return true;
}
return false;
}
private void addListeners() {
DocumentListener defaultDocumentListener = new DefaultDocumentListener();
protractorDirTextField.getDocument().addDocumentListener(defaultDocumentListener);
userConfigurationFileTextField.getDocument().addDocumentListener(defaultDocumentListener);
}
@NbBundle.Messages({"CustomizerProtractor.confirm.autodiscovered.info=Protractor executable was auto-discovered. Please confirm by clicking OK."})
void validateData() {
assert EventQueue.isDispatchThread();
protractor = protractorDirTextField.getText();
userConfigurationFile = userConfigurationFileTextField.getText();
validationResult = new ProtractorPreferencesValidator()
.validateProtractor(protractor)
.validateUserConfigurationFile(project, userConfigurationFile)
.getResult();
if (autoDiscovered) { // auto-discovered, show confirmation message to the user
validationResult.addWarning(new ValidationResult.Message("path", Bundle.CustomizerProtractor_confirm_autodiscovered_info())); // NOI18N
}
changeSupport.fireChange();
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
protractorDirLabel = new javax.swing.JLabel();
protractorDirTextField = new javax.swing.JTextField();
protractorDirBrowseButton = new javax.swing.JButton();
protractorDirInfoLabel = new javax.swing.JLabel();
userConfigurationFileLabel = new javax.swing.JLabel();
userConfigurationFileTextField = new javax.swing.JTextField();
userConfigurationFileBrowseButton = new javax.swing.JButton();
userConfigurationFileInfoLabel = new javax.swing.JLabel();
protractorDirLabel.setLabelFor(protractorDirTextField);
org.openide.awt.Mnemonics.setLocalizedText(protractorDirLabel, org.openide.util.NbBundle.getMessage(CustomizerProtractor.class, "CustomizerProtractor.protractorDirLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(protractorDirBrowseButton, org.openide.util.NbBundle.getMessage(CustomizerProtractor.class, "CustomizerProtractor.protractorDirBrowseButton.text")); // NOI18N
protractorDirBrowseButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
protractorDirBrowseButtonActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(protractorDirInfoLabel, org.openide.util.NbBundle.getMessage(CustomizerProtractor.class, "CustomizerProtractor.protractorDirInfoLabel.text")); // NOI18N
userConfigurationFileLabel.setLabelFor(protractorDirTextField);
org.openide.awt.Mnemonics.setLocalizedText(userConfigurationFileLabel, org.openide.util.NbBundle.getMessage(CustomizerProtractor.class, "CustomizerProtractor.userConfigurationFileLabel.text")); // NOI18N
userConfigurationFileTextField.setColumns(15);
org.openide.awt.Mnemonics.setLocalizedText(userConfigurationFileBrowseButton, org.openide.util.NbBundle.getMessage(CustomizerProtractor.class, "CustomizerProtractor.userConfigurationFileBrowseButton.text")); // NOI18N
userConfigurationFileBrowseButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
userConfigurationFileBrowseButtonActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(userConfigurationFileInfoLabel, org.openide.util.NbBundle.getMessage(CustomizerProtractor.class, "CustomizerProtractor.userConfigurationFileInfoLabel.text")); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(userConfigurationFileLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(userConfigurationFileInfoLabel)
.addGap(0, 0, Short.MAX_VALUE))
.addComponent(userConfigurationFileTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 181, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(userConfigurationFileBrowseButton))
.addGroup(layout.createSequentialGroup()
.addComponent(protractorDirLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(protractorDirInfoLabel)
.addGap(0, 0, Short.MAX_VALUE))
.addGroup(layout.createSequentialGroup()
.addComponent(protractorDirTextField)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(protractorDirBrowseButton)))))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(protractorDirLabel)
.addComponent(protractorDirTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(protractorDirBrowseButton))
.addGap(6, 6, 6)
.addComponent(protractorDirInfoLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(userConfigurationFileLabel)
.addComponent(userConfigurationFileBrowseButton)
.addComponent(userConfigurationFileTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(userConfigurationFileInfoLabel))
);
}// </editor-fold>//GEN-END:initComponents
@NbBundle.Messages("CustomizerProtractor.chooser.protractor=Select Protractor file")
private void protractorDirBrowseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_protractorDirBrowseButtonActionPerformed
assert EventQueue.isDispatchThread();
File file = new FileChooserBuilder(CustomizerProtractor.class)
.setTitle(Bundle.CustomizerProtractor_chooser_protractor())
.setFilesOnly(true)
.setDefaultWorkingDirectory(FileUtil.toFile(project.getProjectDirectory()))
.forceUseOfDefaultWorkingDirectory(true)
.showOpenDialog();
if (file != null) {
protractorDirTextField.setText(file.getAbsolutePath());
}
}//GEN-LAST:event_protractorDirBrowseButtonActionPerformed
@NbBundle.Messages("CustomizerProtractor.chooser.userConfigurationFile=Select Configuration file")
private void userConfigurationFileBrowseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_userConfigurationFileBrowseButtonActionPerformed
assert EventQueue.isDispatchThread();
File file = new FileChooserBuilder(CustomizerProtractor.class)
.setTitle(Bundle.CustomizerProtractor_chooser_userConfigurationFile())
.setFilesOnly(true)
.setDefaultWorkingDirectory(FileUtil.toFile(project.getProjectDirectory()))
.forceUseOfDefaultWorkingDirectory(true)
.addFileFilter(new FileNameExtensionFilter("JS File", "js"))
.setAcceptAllFileFilterUsed(false)
.showOpenDialog();
if (file != null) {
userConfigurationFileTextField.setText(file.getAbsolutePath());
}
}//GEN-LAST:event_userConfigurationFileBrowseButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton protractorDirBrowseButton;
private javax.swing.JLabel protractorDirInfoLabel;
private javax.swing.JLabel protractorDirLabel;
private javax.swing.JTextField protractorDirTextField;
private javax.swing.JButton userConfigurationFileBrowseButton;
private javax.swing.JLabel userConfigurationFileInfoLabel;
private javax.swing.JLabel userConfigurationFileLabel;
private javax.swing.JTextField userConfigurationFileTextField;
// End of variables declaration//GEN-END:variables
//~ Inner classes
private final class DefaultDocumentListener implements DocumentListener {
@Override
public void insertUpdate(DocumentEvent e) {
processChange();
}
@Override
public void removeUpdate(DocumentEvent e) {
processChange();
}
@Override
public void changedUpdate(DocumentEvent e) {
processChange();
}
private void processChange() {
validateData();
}
}
}