blob: eda9dff38bd17a007c89baa716e9956709473271 [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.gsf.testrunner.ui;
import org.netbeans.modules.gsf.testrunner.api.SelfResizingPanel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.io.File;
import java.util.List;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.prefs.Preferences;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.UIResource;
import javax.swing.text.JTextComponent;
import org.netbeans.api.java.classpath.ClassPath;
import org.netbeans.api.project.SourceGroup;
import org.netbeans.modules.gsf.testrunner.api.TestCreatorProvider;
import org.netbeans.modules.gsf.testrunner.plugin.CommonSettingsProvider;
import org.netbeans.modules.gsf.testrunner.plugin.GuiUtilsProvider;
import org.netbeans.modules.gsf.testrunner.ui.spi.TestCreatorConfiguration;
import org.netbeans.modules.gsf.testrunner.ui.spi.TestCreatorConfigurationProvider;
import org.openide.DialogDescriptor;
import org.openide.DialogDisplayer;
import org.openide.awt.Mnemonics;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.util.HelpCtx;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.util.NbPreferences;
import org.openide.util.Pair;
/**
*
* @author vstejskal
* @author Marian Petras
*/
@SuppressWarnings("serial")
public class CommonTestsCfgOfCreate extends SelfResizingPanel implements ChangeListener {
/**
* nodes selected when the Create Tests action was invoked
*/
private FileObject[] activatedFOs;
/** whether the tests will be created for multiple classes */
private boolean multipleClasses;
/** whether a single package/folder is selected */
private boolean singlePackage;
/** whether a single class is selected */
private boolean singleClass;
/** test class name specified in the form (or <code>null</code>) */
private String testClassName;
/** registered change listeners */
private List<ChangeListener> changeListeners;
/** */
private String initialMessage;
/** */
private List<String> testingFrameworks;
// public static final String JUNIT_TEST_FRAMEWORK = "JUnit"; //NOI18N
// public static final String TESTNG_TEST_FRAMEWORK = "TestNG"; //NOI18N
private String selectedTestingFramework = null;
public static final String PROP_TESTING_FRAMEWORK = "testingFramework"; //NOI18N
/**
* is at least one target folder/source group available?
*
* @see #isAcceptable()
*/
private boolean hasTargetFolders = false;
/**
* is the entered class name non-empty and valid?
*
* @see #isAcceptable()
*/
private boolean classNameValid;
/**
* is the current form contents acceptable?
*
* @see #isAcceptable()
*/
private boolean isAcceptable;
/**
* is the current project a j2me project?
*
*/
private boolean isJ2meProject;
/** layer index for a message about an empty set of target folders */
private static final int MSG_TYPE_NO_TARGET_FOLDERS = 0;
/** layer index for a message about invalid class name */
private static final int MSG_TYPE_CLASSNAME_INVALID = 1;
/** layer index for a message about non-default class name */
private static final int MSG_TYPE_CLASSNAME_NOT_DEFAULT = 2;
/** layer index for a message about modified files */
private static final int MSG_TYPE_MODIFIED_FILES = 3;
/** layer index for a message about j2me project type */
private static final int MSG_TYPE_J2ME_PROJECT = 4;
/** layer index for a message about updating a single test class */
private static final int MSG_TYPE_UPDATE_SINGLE_TEST_CLASS = 5;
/** layer index for a message about updating all test classes */
private static final int MSG_TYPE_UPDATE_ALL_TEST_CLASSES = 6;
/** layer index for a message about error/warning in the configuration panel */
private static final int MSG_TYPE_CONFIGURATION_PANEL_ERROR = 7;
/** */
private MessageStack msgStack = new MessageStack(8);
private Collection<SourceGroup> createdSourceRoots = new ArrayList<SourceGroup>();
private final JPanel jPanel = new JPanel();
private TestCreatorConfiguration testCreatorConfiguration;
private Map<String, Object> configurationPanelProperties;
private static final Logger LOGGER = Logger.getLogger(CommonTestsCfgOfCreate.class.getName());
public CommonTestsCfgOfCreate(FileObject[] activatedFOs) {
assert (activatedFOs != null) && (activatedFOs.length != 0);
this.activatedFOs = activatedFOs;
}
/**
* Creates a configuration panel.
*
* @param nodes nodes selected when the Create Tests action was invoked
* @param isShowMsgFilesWillBeSaved if {@code true} then a warning message
* like "Warning: All modified files will be saved." will be
* displayed on the panel, otherwise (i.e. if {@code false}) then
* the message won't be displayed.
*/
@NbBundle.Messages({"MSG_J2ME_PROJECT_TYPE=Tests cannot be created for this project type. Please use the New File wizard to create a JMUnit test instead.",
"MSG_MODIFIED_FILES=Warning: All modified files will be saved."
})
public void createCfgPanel(boolean isShowMsgFilesWillBeSaved, boolean isJ2meProject) {
// assert (nodes != null) && (nodes.length != 0);
// this.nodes = nodes;
multipleClasses = checkMultipleClasses();
this.isJ2meProject = isJ2meProject;
initBundle();
try {
initComponents();
if(isShowMsgFilesWillBeSaved) {
String msg = Bundle.MSG_MODIFIED_FILES();
setMessage(msg, MSG_TYPE_MODIFIED_FILES);
}
if(isJ2meProject) {
setMessage(Bundle.MSG_J2ME_PROJECT_TYPE(), MSG_TYPE_J2ME_PROJECT);
}
setBorder(BorderFactory.createEmptyBorder(12, 12, 0, 11));
addAccessibleDescriptions();
initializeCheckBoxStates();
if (testCreatorConfiguration != null) {
fillFormData();
}
checkAcceptability();
/*
* checkAcceptability() must not be called
* before initializeCheckBoxStates() and fillFormData()
* setupUserInteraction must not be called
* before initializeCheckBoxStates()
*/
} finally {
unlinkBundle();
}
}
@NbBundle.Messages({
"CommonTestsCfgOfCreate_AD=Create Tests",
"CommonTestsCfgOfCreate_clsName_toolTip=Name of the test class",
"CommonTestsCfgOfCreate_clsName_AN=Test Class Name",
"CommonTestsCfgOfCreate_clsName_AD=Name of the test class to be created",
"CommonTestsCfgOfCreate_location_toolTip=Target source root for the test class",
"CommonTestsCfgOfCreate_location_AN=Test Class Location",
"CommonTestsCfgOfCreate_location_AD=Target source root for the test class",
"CommonTestsCfgOfCreate_framework_toolTip=Testing framework for the test class",
"CommonTestsCfgOfCreate_framework_AN=Test Class Testing framework",
"CommonTestsCfgOfCreate_framework_AD=Testing framework for the test class"
})
private void addAccessibleDescriptions() {
// window
this.getAccessibleContext().setAccessibleDescription(Bundle.CommonTestsCfgOfCreate_AD());
// text-field and combo-box
if (this.tfClassName != null) {
this.tfClassName.setToolTipText(
Bundle.CommonTestsCfgOfCreate_clsName_toolTip());
this.tfClassName.getAccessibleContext().setAccessibleName(
Bundle.CommonTestsCfgOfCreate_clsName_AN());
this.tfClassName.getAccessibleContext().setAccessibleDescription(
Bundle.CommonTestsCfgOfCreate_clsName_AD());
}
this.cboxLocation.setToolTipText(
Bundle.CommonTestsCfgOfCreate_location_toolTip());
this.cboxLocation.getAccessibleContext().setAccessibleName(
Bundle.CommonTestsCfgOfCreate_location_AN());
this.cboxLocation.getAccessibleContext().setAccessibleDescription(
Bundle.CommonTestsCfgOfCreate_location_AD());
this.cboxLocation.setToolTipText(
Bundle.CommonTestsCfgOfCreate_framework_toolTip());
this.cboxLocation.getAccessibleContext().setAccessibleName(
Bundle.CommonTestsCfgOfCreate_framework_AN());
this.cboxLocation.getAccessibleContext().setAccessibleDescription(
Bundle.CommonTestsCfgOfCreate_framework_AD());
}
/**
* Checks whether multiple classes may be selected.
* It also detects whether exactly one package/folder or exactly one class
* is selected and sets values of variables {@link #singlePackage}
* and {@link #singleClass} accordingly.
*
* @return <code>false</code> if there is exactly one node selected
* and the node represents a single <code>DataObject</code>,
* not a folder or another <code>DataObject</code> container;
* <code>true</code> otherwise
*/
private boolean checkMultipleClasses() {
if (activatedFOs.length > 1) {
return true;
}
singleClass = false;
FileObject fo = activatedFOs[0];
if (fo != null) {
singlePackage = fo.isFolder();
singleClass = fo.isData();
}
return !singleClass;
}
@NbBundle.Messages({"MSG_UPDATE_SINGLE_TEST_CLASS=The existing test class will be updated.",
"MSG_UPDATE_ALL_TEST_CLASSES=Any existing test classes will be updated."})
private void checkUpdatingExistingTestClass() {
if(tfClassName == null) {
setMessage(Bundle.MSG_UPDATE_ALL_TEST_CLASSES(), MSG_TYPE_UPDATE_ALL_TEST_CLASSES);
} else {
FileObject locationFO = getTargetFolder();
if (locationFO != null) {
String targetFolderPath = FileUtil.toFile(locationFO).getAbsolutePath();
String className = tfClassName.getText();
int index = className.lastIndexOf('.'); // index == -1 most probably means class is under <default package>
String packageName = index == -1 ? "" : className.substring(0, index);
String fileName = index == -1 ? className : className.substring(index + 1);
FileObject testFolderFO = FileUtil.toFileObject(new File(targetFolderPath.concat(File.separator).concat(packageName.replace(".", "/"))));
if(testFolderFO != null) {
for(FileObject testClassFO : testFolderFO.getChildren()) {
if(testClassFO.getName().equals(fileName)) {
setMessage(Bundle.MSG_UPDATE_SINGLE_TEST_CLASS(), MSG_TYPE_UPDATE_SINGLE_TEST_CLASS);
return;
}
}
}
}
setMessage(null, MSG_TYPE_UPDATE_SINGLE_TEST_CLASS);
}
}
/**
* Displays a configuration dialog and updates JUnit options according
* to the user's settings.
*
* @param nodes nodes selected when the Create Test action was invoked
*/
@NbBundle.Messages({"CommonTestsCfgOfCreate_Title=Create/Update Tests",
"LBL_OK=OK",
"AN_OK=Confirm options",
"AD_OK=Confirm options"
})
public boolean configure() {
String title = Bundle.CommonTestsCfgOfCreate_Title();
String btnTxt = Bundle.LBL_OK();
String btnAN = Bundle.AN_OK();
String btnAD = Bundle.AD_OK();
// create and display the dialog:
ChangeListener changeListener;
final JButton btnOK = new JButton(btnTxt);
btnOK.getAccessibleContext().setAccessibleName(btnAN);//NbBundle.getMessage(GuiUtils.class, "AN_OK"));
btnOK.getAccessibleContext().setAccessibleDescription(btnAD);//NbBundle.getMessage(GuiUtils.class, "AD_OK"));
btnOK.setEnabled(isAcceptable());
addChangeListener(changeListener = new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
btnOK.setEnabled(isAcceptable());
}
});
Object returned = DialogDisplayer.getDefault().notify(
new DialogDescriptor (
this,
title,
true, //modal
new Object[] {btnOK, DialogDescriptor.CANCEL_OPTION},
btnOK, //initial value
DialogDescriptor.DEFAULT_ALIGN,
new HelpCtx("org.netbeans.modules.gsf.testrunner.CommonTestsCfgOfCreate"),
(ActionListener) null
));
removeChangeListener(changeListener);
if (returned == btnOK) {
rememberCheckBoxStates();
setLastSelectedTestingFramework();
testClassName = (tfClassName != null) ? tfClassName.getText()
: null;
return true;
}
return false;
}
/**
* Returns whether a test for a single class is to be created.
*
* @return true if there is only one node selected and the node
* represents a class
*/
public boolean isSingleClass() {
return singleClass;
}
/**
* Returns whether integration tests are to be created.
*
* @return true if integration tests are to be created
*/
public boolean isIntegrationTests() {
if (chkIntegrationTests != null) { // java provider found
return chkIntegrationTests.isSelected();
}
return false;
}
public boolean isSinglePackage() {
return singlePackage;
}
/**
* Get properties from configuration panel inside "Create Tests" dialog. The
* configuration panel is bound to the selected testing framework inside
* this dialog.
*
* @return map of properties from configuration panel inside "Create Tests"
* dialog
*/
public Map<String, Object> getConfigurationPanelProperties() {
return Collections.unmodifiableMap(configurationPanelProperties);
}
/**
* Returns the class name entered in the text-field.
*
* @return class name entered in the form,
* or <code>null</code> if the form did not contain
* the field for entering class name
*/
public String getTestClassName() {
return testClassName;
}
/** resource bundle used during initialization of this panel */
public ResourceBundle bundle;
/**
* Reads JUnit settings and initializes checkboxes accordingly.
*
* @see #rememberCheckBoxStates
*/
private void initializeCheckBoxStates() {
if (chkIntegrationTests != null) {
Collection<? extends CommonSettingsProvider> providers = Lookup.getDefault().lookupAll(CommonSettingsProvider.class);
for (CommonSettingsProvider provider : providers) {
chkIntegrationTests.setSelected(provider.isGenerateIntegrationTests());
break;
}
}
}
/**
* Stores settings given by checkbox states to JUnit settings.
*
* @see #initializeCheckBoxStatesf
*/
private void rememberCheckBoxStates() {
Collection<? extends CommonSettingsProvider> providers = Lookup.getDefault().lookupAll(CommonSettingsProvider.class);
for (CommonSettingsProvider provider : providers) {
provider.setGenerateIntegrationTests(isIntegrationTests());
break;
}
if (testCreatorConfiguration != null) {
TestCreatorConfiguration.Context context = new TestCreatorConfiguration.Context(multipleClasses, new CommonCfgOfCreateCallback(this));
testCreatorConfiguration.persistConfigurationPanel(context);
configurationPanelProperties = context.getProperties();
}
}
private void setLastSelectedTestingFramework() {
getPreferences().put(PROP_TESTING_FRAMEWORK, selectedTestingFramework);
}
private String getLastSelectedTestingFramework() {
return getPreferences().get(PROP_TESTING_FRAMEWORK, "");
}
private static Preferences getPreferences() {
return NbPreferences.forModule(CommonTestsCfgOfCreate.class);
}
/**
* Loads a resource bundle so that it can be used during intialization
* of this panel.
*
* @see #unlinkBundle
*/
private void initBundle() {
Collection<? extends GuiUtilsProvider> providers = Lookup.getDefault().lookupAll(GuiUtilsProvider.class);
for (GuiUtilsProvider provider : providers) {
bundle = provider.getBundle();
break;
}
}
/**
* Nulls the resource bundle so that it is not held in memory when it is
* not used.
*
* @see #initBundle
*/
private void unlinkBundle() {
bundle = null;
}
private static class CommonCfgOfCreateCallback implements TestCreatorConfiguration.Callback {
private final CommonTestsCfgOfCreate commonCfgPanel;
public CommonCfgOfCreateCallback(CommonTestsCfgOfCreate commonCfgPanel) {
this.commonCfgPanel = commonCfgPanel;
}
@Override
public void checkAcceptability() {
commonCfgPanel.checkAcceptability();
}
}
/**
* This method is called from within the constructor to initialize the form.
*/
private void initComponents() {
jPanel.setLayout(new BorderLayout(0, 12));
jPanel.add(createNameAndLocationPanel(), BorderLayout.NORTH);
jPanel.add(createMessagePanel(), BorderLayout.CENTER);
jPanel.add(createCodeGenPanel(), BorderLayout.SOUTH);
add(jPanel);
}
private String getTestingFrameworkSuffix() {
Object tf = cboxFramework.getSelectedItem();
if(tf == null) {
return "";
}
String testngFramework = "";
Collection<? extends GuiUtilsProvider> providers = Lookup.getDefault().lookupAll(GuiUtilsProvider.class);
for (GuiUtilsProvider provider : providers) {
testngFramework = provider.getTestngFramework();
break;
}
return tf.toString().equals(testngFramework) ? "NG" : ""; //NOI18N
}
private void fireFrameworkChanged() {
setSelectedTestingFramework();
Collection<? extends GuiUtilsProvider> providers = Lookup.getDefault().lookupAll(GuiUtilsProvider.class);
for (GuiUtilsProvider provider : providers) {
if(selectedTestingFramework != null && selectedTestingFramework.equals(provider.getJunitFramework())) {
chkIntegrationTests.setEnabled(true);
} else {
chkIntegrationTests.setEnabled(false);
}
break;
}
testCreatorConfiguration = null;
Collection<? extends TestCreatorConfigurationProvider> panelProviders = Lookup.getDefault().lookupAll(TestCreatorConfigurationProvider.class);
for (TestCreatorConfigurationProvider panelProvider : panelProviders) {
TestCreatorConfiguration testCreatorConf = panelProvider.createTestCreatorConfiguration(activatedFOs);
if (selectedTestingFramework != null && testCreatorConf.canHandleProject(selectedTestingFramework)) {
testCreatorConfiguration = testCreatorConf;
break;
}
}
if (testCreatorConfiguration != null) {
fillFormData();
checkAcceptability();
TestCreatorConfiguration.Context context = new TestCreatorConfiguration.Context(multipleClasses, new CommonCfgOfCreateCallback(this));
Component bottomPanel = testCreatorConfiguration.getConfigurationPanel(context);
BorderLayout layout = (BorderLayout) jPanel.getLayout();
jPanel.remove(layout.getLayoutComponent(BorderLayout.SOUTH));
jPanel.add(bottomPanel, BorderLayout.SOUTH);
jPanel.revalidate();
}
shouldShowClassToTestInfo();
updateClassName();
checkUpdatingExistingTestClass();
}
private void updateClassName() {
if (tfClassName != null) {
boolean shouldShowClassNameInfo = shouldShowClassNameInfo();
tfClassName.setVisible(shouldShowClassNameInfo);
lblClassName.setVisible(shouldShowClassNameInfo);
if (shouldShowClassNameInfo) {
FileObject fileObj = activatedFOs[0];
ClassPath cp = ClassPath.getClassPath(fileObj, ClassPath.SOURCE);
if (cp != null) {
String className = cp.getResourceName(fileObj, '.', false);
String suffix = (selectedTestingFramework != null && selectedTestingFramework.equals(TestCreatorProvider.FRAMEWORK_SELENIUM))
|| (chkIntegrationTests != null && chkIntegrationTests.isEnabled() && chkIntegrationTests.isSelected()) ? TestCreatorProvider.INTEGRATION_TEST_CLASS_SUFFIX : TestCreatorProvider.TEST_CLASS_SUFFIX;
String prefilledName = className + getTestingFrameworkSuffix() + suffix;
tfClassName.setText(prefilledName);
tfClassName.setDefaultText(prefilledName);
tfClassName.setCaretPosition(prefilledName.length());
}
}
}
}
private boolean shouldShowClassNameInfo() {
if (testCreatorConfiguration != null) {
return testCreatorConfiguration.showClassNameInfo();
}
return true;
}
private boolean shouldShowClassToTestInfo() {
boolean shouldShowClassToTestInfo = true;
if (testCreatorConfiguration != null) {
shouldShowClassToTestInfo = testCreatorConfiguration.showClassToTestInfo();
}
lblClassToTest.setVisible(shouldShowClassToTestInfo);
if(lblClassToTestValue != null) {
// single class/package was selected by the user
lblClassToTestValue.setVisible(shouldShowClassToTestInfo);
}
return shouldShowClassToTestInfo;
}
private void setSelectedTestingFramework() {
Object tf = cboxFramework.getSelectedItem();
if(tf != null) {
selectedTestingFramework = tf.toString();
}
}
public String getSelectedTestingFramework() {
return selectedTestingFramework;
}
public void addTestingFrameworks(ArrayList<String> testingFrameworksToAdd) {
testingFrameworks = new ArrayList<String>();
for(String testingFramework : testingFrameworksToAdd) {
testingFrameworks.add(testingFramework);
}
cboxFramework.setModel(new DefaultComboBoxModel(testingFrameworks.toArray()));
cboxFramework.setSelectedItem(getLastSelectedTestingFramework());
fireFrameworkChanged();
}
public void setPreselectedLocation(Object location) {
if (location != null) {
cboxLocation.setSelectedItem(location);
cboxLocation.setEnabled(false);
}
}
public void setPreselectedFramework(String testingFramework) {
if (testingFramework != null) {
cboxFramework.setSelectedItem(testingFramework);
cboxFramework.setEnabled(false);
setSelectedTestingFramework();
}
}
@NbBundle.Messages({"LBL_PackageToTest=Package:",
"LBL_ClassToTest=&Class to Test:",
"LBL_MultipleClassesSelected=More than one class is selected...",
"LBL_ClassName=Class &Name:",
"LBL_Location=&Location:",
"LBL_Framework=&Framework:"
})
private Component createNameAndLocationPanel() {
JPanel panel = new JPanel();
final boolean askForClassName = singleClass;
lblClassToTest = new JLabel();
lblClassName = askForClassName ? new JLabel() : null;
JLabel lblLocation = new JLabel();
JLabel lblFramework = new JLabel();
String classToTestKey = singlePackage
? Bundle.LBL_PackageToTest()
: singleClass
? Bundle.LBL_ClassToTest()
: Bundle.LBL_MultipleClassesSelected();
String classToTest = classToTestKey;
String classname = Bundle.LBL_ClassName();
String location = Bundle.LBL_Location();
String framework = Bundle.LBL_Framework();
Mnemonics.setLocalizedText(
lblClassToTest,
classToTest);
if (askForClassName) {
Mnemonics.setLocalizedText(
lblClassName,
classname);
}
Mnemonics.setLocalizedText(
lblLocation,
location);
Mnemonics.setLocalizedText(
lblFramework,
framework);
if (singlePackage || singleClass) {
lblClassToTestValue = new JLabel();
}
if (askForClassName) {
tfClassName = new ClassNameTextField();
tfClassName.setChangeListener(this);
}
cboxLocation = new JComboBox();
cboxFramework = new JComboBox();
cboxFramework.addItemListener(new java.awt.event.ItemListener() {
@Override
public void itemStateChanged(java.awt.event.ItemEvent evt) {
// itemStateChanged is fired both on ItemEvent.SELECTED and
// ItemEvent.DESELECTED. React only one time per state change.
if(evt.getStateChange() == ItemEvent.SELECTED) {
fireFrameworkChanged();
}
}
});
if (askForClassName) {
lblClassName.setLabelFor(tfClassName);
}
lblLocation.setLabelFor(cboxLocation);
lblFramework.setLabelFor(cboxFramework);
if (lblClassToTestValue != null) {
Font labelFont = javax.swing.UIManager.getDefaults()
.getFont("TextField.font"); //NOI18N
if (labelFont != null) {
lblClassToTestValue.setFont(labelFont);
}
}
Collection<? extends GuiUtilsProvider> providers = Lookup.getDefault().lookupAll(GuiUtilsProvider.class);
if (!providers.isEmpty()) {
String[] chkBoxIDs = new String[1];
JCheckBox[] chkBoxes;
for (GuiUtilsProvider provider : providers) {
chkBoxIDs = new String[]{provider.getCheckboxText("CHK_INTEGRATION_TESTS")};
break;
}
chkBoxes = new JCheckBox[chkBoxIDs.length];
for (GuiUtilsProvider provider : providers) {
chkBoxes = provider.createCheckBoxes(chkBoxIDs);
break;
}
chkIntegrationTests = chkBoxes[0];
if (chkIntegrationTests != null) { // java provider found
chkIntegrationTests.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
updateClassName();
checkUpdatingExistingTestClass();
}
});
}
}
panel.setLayout(new GridBagLayout());
GridBagConstraints gbcLeft = new GridBagConstraints();
gbcLeft.anchor = GridBagConstraints.WEST;
gbcLeft.insets.bottom = 12;
gbcLeft.insets.right = 6;
GridBagConstraints gbcRight = new GridBagConstraints();
gbcRight.anchor = GridBagConstraints.WEST;
gbcRight.insets.bottom = 12;
gbcRight.weightx = 1.0f;
gbcRight.fill = GridBagConstraints.BOTH;
gbcRight.gridwidth = GridBagConstraints.REMAINDER;
if (lblClassToTestValue != null) {
panel.add(lblClassToTest, gbcLeft);
panel.add(lblClassToTestValue, gbcRight);
} else {
panel.add(lblClassToTest, gbcRight);
}
shouldShowClassToTestInfo();
if (askForClassName) {
panel.add(lblClassName, gbcLeft);
panel.add(tfClassName, gbcRight);
}
panel.add(lblLocation, gbcLeft);
panel.add(cboxLocation, gbcRight);
gbcLeft.insets.bottom = 0;
gbcRight.insets.bottom = 0;
panel.add(lblFramework, gbcLeft);
panel.add(cboxFramework, gbcRight);
if (chkIntegrationTests != null) { // java provider found
panel.add(chkIntegrationTests, gbcRight);
}
return panel;
}
/**
*/
private void checkClassNameValidity() {
if (tfClassName == null) {
classNameValid = true;
return;
}
String key = null;
final int state = tfClassName.getStatus();
switch (state) {
case ClassNameTextField.STATUS_EMPTY:
key = "MSG_ClassnameMustNotBeEmpty"; //NOI18N
break;
case ClassNameTextField.STATUS_INVALID:
key = "MSG_InvalidClassName"; //NOI18N
break;
case ClassNameTextField.STATUS_VALID_NOT_DEFAULT:
key = "MSG_ClassNameNotDefault"; //NOI18N
break;
case ClassNameTextField.STATUS_VALID_END_NOT_TEST:
key = "MSG_ClassNameEndNotTest"; //NOI18N
break;
}
if (state != ClassNameTextField.STATUS_VALID_NOT_DEFAULT) {
setMessage(null, MSG_TYPE_CLASSNAME_NOT_DEFAULT);
}
String message = "";
if (key != null) {
Collection<? extends GuiUtilsProvider> providers = Lookup.getDefault().lookupAll(GuiUtilsProvider.class);
for (GuiUtilsProvider provider : providers) {
message = provider.getMessageFor(key);
break;
}
}
setMessage((key != null)
? message
: null,
MSG_TYPE_CLASSNAME_INVALID);
classNameValid =
(state == ClassNameTextField.STATUS_VALID)
|| (state == ClassNameTextField.STATUS_VALID_NOT_DEFAULT);
}
/**
* This method gets called if status of contents of the Class Name
* text field changes. See <code>STATUS_xxx</code> constants
* in class <code>ClassNameTextField</code>.
*
* @param e event describing the state change event
* (unused in this method)
*/
@Override
public void stateChanged(ChangeEvent e) {
checkClassNameValidity();
checkAcceptability();
}
/**
*/
private void checkAcceptability() {
final boolean wasAcceptable = isAcceptable;
isAcceptable = hasTargetFolders && classNameValid && !isJ2meProject && isConfigurationPanelValid();
if (isAcceptable != wasAcceptable) {
fireStateChange();
}
}
@NbBundle.Messages({"# {0} - test creator configuration",
"MSG_CONFIGURATION_PANEL_INVALIDITY=The configuration panel is invalid but no error message is available for: {0}",
"MSG_CONFIGURATION_PANEL_INVALIDITY_SHORT=The configuration panel is invalid but no error message is available."})
private boolean isConfigurationPanelValid() {
if (testCreatorConfiguration != null) {
boolean valid = testCreatorConfiguration.isValid();
String errorMessage = testCreatorConfiguration.getErrorMessage();
if (valid) {
// if errorMessage is null currently displayed message (if any) will be removed
setMessage(errorMessage, MSG_TYPE_CONFIGURATION_PANEL_ERROR);
} else {
if(errorMessage == null) {
LOGGER.info(Bundle.MSG_CONFIGURATION_PANEL_INVALIDITY(testCreatorConfiguration.getClass().toString()));
setMessage(Bundle.MSG_CONFIGURATION_PANEL_INVALIDITY_SHORT(), MSG_TYPE_CONFIGURATION_PANEL_ERROR);
} else {
setMessage(errorMessage, MSG_TYPE_CONFIGURATION_PANEL_ERROR);
}
}
return valid;
}
return true;
}
/**
* Are the values filled in the form acceptable?
*
* @see #addChangeListener
*/
private boolean isAcceptable() {
return isAcceptable;
}
/**
* This method is called the first time this panel's children are painted.
* By default, this method just calls {@link #adjustWindowSize()}.
*
* @param g <code>Graphics</code> used to paint this panel's children
*/
@Override
protected void paintedFirstTime(java.awt.Graphics g) {
if (initialMessage != null) {
displayMessage(initialMessage);
initialMessage = null;
}
}
/**
* Displays a given message in the message panel and resizes the dialog
* if necessary. If the message cannot be displayed immediately,
* because of this panel not displayed (painted) yet, displaying the message
* is deferred until this panel is painted.
*
* @param message message to be displayed, or <code>null</code> if
* the currently displayed message (if any) should be
* removed
*/
private void setMessage(final String message, final int msgType) {
String msgToDisplay = msgStack.setMessage(msgType, message);
if (msgToDisplay == null) {
return; //no change
}
/* display the message: */
if (!isPainted()) {
initialMessage = msgToDisplay;
} else {
displayMessage(msgToDisplay);
}
}
/**
* Displays a given message in the message panel and resizes the dialog
* if necessary.
*
* @param message message to be displayed, or <code>null</code> if
* the currently displayed message (if any) should be
* removed
* @see #adjustWindowSize()
*/
private void displayMessage(String message) {
if (message == null) {
message = ""; //NOI18N
}
txtAreaMessage.setText(message);
adjustWindowSize();
}
/**
* Creates a text component to be used as a multi-line, automatically
* wrapping label.
* <p>
* <strong>Restriction:</strong><br>
* The component may have its preferred size very wide.
*
* @return created multi-line text component
*/
private Component createMessagePanel() {
if (txtAreaMessage == null) {
JTextArea textArea = new JTextArea("");
textArea.setEditable(false);
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
textArea.setEnabled(false);
textArea.setOpaque(false);
textArea.setColumns(25);
Color color = UIManager.getColor("nb.errorForeground"); //NOI18N
if (color == null) {
color = new Color(89, 79, 191); //RGB suggested by Bruce in #28466
}
textArea.setDisabledTextColor(color);
txtAreaMessage = textArea;
}
return txtAreaMessage;
}
/**
* Creates a panel containing controls for settings code generation options.
*
* @return created panel
*/
private Component createCodeGenPanel() {
Component bottomPanel = new JPanel();
bottomPanel.setPreferredSize(new Dimension(447, 344));
testCreatorConfiguration = null;
Collection<? extends TestCreatorConfigurationProvider> panelProviders = Lookup.getDefault().lookupAll(TestCreatorConfigurationProvider.class);
for (TestCreatorConfigurationProvider panelProvider : panelProviders) {
TestCreatorConfiguration testCreatorConf = panelProvider.createTestCreatorConfiguration(activatedFOs);
if (selectedTestingFramework != null && testCreatorConf.canHandleProject(selectedTestingFramework)) {
testCreatorConfiguration = testCreatorConf;
break;
}
}
if (testCreatorConfiguration != null) {
TestCreatorConfiguration.Context context = new TestCreatorConfiguration.Context(multipleClasses, new CommonCfgOfCreateCallback(this));//bundle);
bottomPanel = testCreatorConfiguration.getConfigurationPanel(context);
return bottomPanel;
}
return bottomPanel;
}
/**
* Adds a border and a title around a given component.
* If the component already has some border, it is overridden (not kept).
*
* @param component component the border and title should be added to
* @param insets insets between the component and the titled border
* @param title text of the title
*/
private static void addTitledBorder(JComponent component,
Insets insets,
String title) {
Border insideBorder = BorderFactory.createEmptyBorder(
insets.top, insets.left, insets.bottom, insets.right);
Border outsideBorder = new TitledBorder(
BorderFactory.createEtchedBorder(), title);
component.setBorder(new CompoundBorder(outsideBorder, insideBorder));
}
/**
*/
public FileObject getTargetFolder() {
Object selectedLocation = cboxLocation.getSelectedItem();
if (selectedLocation == null) {
return null;
}
if (selectedLocation instanceof SourceGroup) {
return ((SourceGroup) selectedLocation).getRootFolder();
}
assert selectedLocation instanceof FileObject; //root folder
return (FileObject) selectedLocation;
}
/**
* Initializes form in the Test Settings panel of the dialog.
*/
@NbBundle.Messages("DefaultPackageName=<default package>")
private void fillFormData() {
final FileObject fileObj = activatedFOs[0];
if (singleClass) {
assert activatedFOs.length == 1;
String className = "";
String prefilledName = "";
if (testCreatorConfiguration != null) {
boolean isTestNG = !getTestingFrameworkSuffix().isEmpty();
boolean isSelenium = isIntegrationTests()
|| (selectedTestingFramework != null && selectedTestingFramework.equals(TestCreatorProvider.FRAMEWORK_SELENIUM));
Pair<String, String> testClassNames = testCreatorConfiguration.getSourceAndTestClassNames(fileObj, isTestNG, isSelenium);
className = testClassNames.first();
prefilledName = testClassNames.second();
}
lblClassToTestValue.setText(className);
if (tfClassName != null) {
tfClassName.setText(prefilledName);
tfClassName.setDefaultText(prefilledName);
tfClassName.setCaretPosition(prefilledName.length());
}
} else if (singlePackage) {
assert activatedFOs.length == 1;
ClassPath cp = ClassPath.getClassPath(fileObj, ClassPath.SOURCE);
String packageName = (cp == null) ? Bundle.DefaultPackageName() : cp.getResourceName(fileObj, '.', true);
lblClassToTestValue.setText(packageName);
} else {
//PENDING
}
setupLocationChooser(fileObj);
checkClassNameValidity();
}
@NbBundle.Messages({
"# {0} - folder",
"MSG_NoTestTarget_Fo=Unable to locate test package folders for folder {0}. The project must contain a test package folder to create tests. You can designate test package folders for your project in the Sources pane of the project Properties dialog.",
"# {0} - file",
"MSG_NoTestTarget_Fi=Unable to locate test package folder for file {0}. The project must contain a test package folder to create tests. You can designate test package folders for your project in the Sources pane of the project Properties dialog."
})
private void setupLocationChooser(FileObject refFileObject) {
Object[] targetFolders = null;
if (testCreatorConfiguration != null) {
targetFolders = testCreatorConfiguration.getTestSourceRoots(createdSourceRoots, refFileObject);
}
if (targetFolders != null && targetFolders.length != 0) {
hasTargetFolders = true;
cboxLocation.setModel(new DefaultComboBoxModel(targetFolders));
cboxLocation.setRenderer(new LocationChooserRenderer());
setMessage(null, MSG_TYPE_NO_TARGET_FOLDERS);
} else {
hasTargetFolders = false;
if(testingFrameworks != null) {
//PENDING - message text:
String msgNoTargetsFound = refFileObject.isFolder()? Bundle.MSG_NoTestTarget_Fo(refFileObject.getNameExt()) : Bundle.MSG_NoTestTarget_Fi(refFileObject.getNameExt());
setMessage(msgNoTargetsFound, MSG_TYPE_NO_TARGET_FOLDERS);
// do not disable all components as user might want to select a different testing provider
// disableComponents();
}
}
}
public Collection<? extends SourceGroup> getCreatedSourceRoots() {
return Collections.unmodifiableCollection(createdSourceRoots);
}
/**
* Renderer which specially handles values of type
* <code>SourceGroup</code> and <code>FileObject</code>.
* It displays display names of these objects, instead of their default
* string representation (<code>toString()</code>).
*
* @see SourceGroup#getDisplayName()
* @see FileUtil#getFileDisplayName(FileObject)
*/
private final class LocationChooserRenderer extends JLabel implements ListCellRenderer, UIResource {
public LocationChooserRenderer () {
setOpaque(true);
}
@Override
public Component getListCellRendererComponent(
JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus) {
// #93658: GTK needs name to render cell renderer "natively"
setName("ComboBox.listRenderer"); // NOI18N
String text = value instanceof SourceGroup
? ((SourceGroup) value).getDisplayName()
: value instanceof FileObject
? FileUtil.getFileDisplayName((FileObject) value)
: value.toString();
setText(text);
if ( isSelected ) {
setBackground(list.getSelectionBackground());
setForeground(list.getSelectionForeground());
}
else {
setBackground(list.getBackground());
setForeground(list.getForeground());
}
return this;
}
// #93658: GTK needs name to render cell renderer "natively"
@Override
public String getName() {
String name = super.getName();
return name == null ? "ComboBox.renderer" : name; // NOI18N
}
}
/**
* Registers a change listener.
* Registered change listeners are notified when acceptability
* of values in the form changes.
*
* @param l listener to be registered
* @see #isAcceptable
* @see #removeChangeListener
*/
private void addChangeListener(ChangeListener l) {
if (changeListeners == null) {
changeListeners = new ArrayList<ChangeListener>(3);
}
changeListeners.add(l);
}
/**
* Unregisters the given change listener.
* If the given listener has not been registered before, calling this
* method does not have any effect.
*
* @param l change listener to be removed
* @see #addChangeListener
*/
private void removeChangeListener(ChangeListener l) {
if (changeListeners != null
&& changeListeners.remove(l)
&& changeListeners.isEmpty()) {
changeListeners = null;
}
}
/**
* Notifies all registered change listeners about a change.
*
* @see #addChangeListener
*/
private void fireStateChange() {
if (changeListeners != null) {
ChangeEvent e = new ChangeEvent(this);
for (Iterator i = changeListeners.iterator(); i.hasNext(); ) {
((ChangeListener) i.next()).stateChanged(e);
}
}
}
/**
* Disables all interactive visual components of this dialog
* except the OK, Cancel and Help buttons.
*/
private void disableComponents() {
final Stack<Container> stack = new Stack<Container>();
stack.push(this);
while (!stack.empty()) {
Container container = stack.pop();
Component comps[] = container.getComponents();
for (int i = 0; i < comps.length; i++) {
final java.awt.Component comp = comps[i];
if (comp == txtAreaMessage) {
continue;
}
if (comp instanceof JPanel) {
JPanel panel = (JPanel) comp;
stack.push(panel);
final Border border = panel.getBorder();
if (border != null) {
disableBorderTitles(border);
}
continue;
}
comp.setEnabled(false);
if (comp instanceof java.awt.Container) {
Container nestedCont = (Container) comp;
if (nestedCont.getComponentCount() != 0) {
stack.push(nestedCont);
}
}
}
}
}
/**
*/
private static void disableBorderTitles(Border border) {
if (border instanceof TitledBorder) {
disableBorderTitle((TitledBorder) border);
return;
}
if (!(border instanceof CompoundBorder)) {
return;
}
Stack<CompoundBorder> stack = new Stack<CompoundBorder>();
stack.push((CompoundBorder) border);
while (!stack.empty()) {
CompoundBorder cb = stack.pop();
Border b;
b = cb.getOutsideBorder();
if (b instanceof CompoundBorder) {
stack.push((CompoundBorder) b);
} else if (b instanceof TitledBorder) {
disableBorderTitle((TitledBorder) b);
}
b = cb.getInsideBorder();
if (b instanceof CompoundBorder) {
stack.push((CompoundBorder) b);
} else if (b instanceof TitledBorder) {
disableBorderTitle((TitledBorder) b);
}
}
}
/**
*/
private static void disableBorderTitle(TitledBorder border) {
final Color color = UIManager.getColor(
"Label.disabledForeground"); //NOI18N
if (color != null) {
border.setTitleColor(color);
}
}
private JLabel lblClassToTest;
private JLabel lblClassToTestValue;
private JLabel lblClassName;
private ClassNameTextField tfClassName;
private JTextComponent txtAreaMessage;
private JComboBox cboxLocation;
private JComboBox cboxFramework;
private JCheckBox chkIntegrationTests;
}