| /* |
| * 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(); |
| } |
| |
| } |
| |
| } |