package org.netbeans.gradle.project.tasks.vars;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.DefaultComboBoxModel;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.ParallelGroup;
import javax.swing.GroupLayout.SequentialGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.LayoutStyle;
import javax.swing.WindowConstants;
import org.jtrim.utils.ExceptionHelper;
import org.netbeans.gradle.project.NbIcons;
import org.netbeans.gradle.project.NbStrings;
import org.netbeans.gradle.project.util.StringUtils;
@SuppressWarnings("serial")
public final class TaskVariableQueryDialog extends JDialog {
private static final Map<String, UserVariableFactory> FACTORY_MAP = variableFactoryMap();
private static final Map<String, Integer> TYPE_ORDER = typeOrderMap();
private final List<UserVariable> variablesToQuery;
private TaskVariableQueryDialog(Collection<DisplayedTaskVariable> variablesToQuery) {
super((Frame)null, true);
this.variablesToQuery = toUserVariables(variablesToQuery);
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
setIconImage(NbIcons.getGradleIcon());
}
private static Map<String, UserVariableFactory> variableFactoryMap() {
Map<String, UserVariableFactory> result = new HashMap<>();
result.put(VariableTypeDescription.TYPE_NAME_BOOL, BoolVariable.FACTORY);
result.put(VariableTypeDescription.TYPE_NAME_ENUM, EnumVariable.FACTORY);
result.put(VariableTypeDescription.TYPE_NAME_STRING, StringVariable.FACTORY);
return Collections.unmodifiableMap(result);
}
private static Map<String, Integer> typeOrderMap() {
Map<String, Integer> result = new HashMap<>();
result.put(VariableTypeDescription.TYPE_NAME_STRING, 0);
result.put(VariableTypeDescription.TYPE_NAME_ENUM, 1);
result.put(VariableTypeDescription.TYPE_NAME_BOOL, 2);
return Collections.unmodifiableMap(result);
}
private static int getTypeOrder(DisplayedTaskVariable var) {
Integer order = TYPE_ORDER.get(var.getTypeDescription().getTypeName());
return order != null ? order : 0;
}
private static List<UserVariable> toUserVariables(Collection<DisplayedTaskVariable> variables) {
List<UserVariable> result = new ArrayList<>(variables.size());
for (DisplayedTaskVariable variable: variables) {
String tpyeName = variable.getTypeDescription().getTypeName();
UserVariableFactory variableFactory = FACTORY_MAP.get(tpyeName);
if (variableFactory == null) {
variableFactory = StringVariable.FACTORY;
}
result.add(variableFactory.createVariable(variable));
}
Collections.sort(result, new Comparator<UserVariable>() {
@Override
public int compare(UserVariable o1, UserVariable o2) {
DisplayedTaskVariable var1 = o1.getDisplayedVariable();
DisplayedTaskVariable var2 = o2.getDisplayedVariable();
int typeOrder1 = getTypeOrder(var1);
int typeOrder2 = getTypeOrder(var2);
if (typeOrder1 != typeOrder2) {
return typeOrder1 < typeOrder2 ? -1 : 1;
}
return StringUtils.STR_CMP.compare(var1.getDisplayName(), var2.getDisplayName());
}
});
return result;
}
private ParallelGroup createParallelGroup(GroupLayout layout) {
ParallelGroup group = layout.createParallelGroup(GroupLayout.Alignment.LEADING);
for (UserVariable variable: variablesToQuery) {
variable.addToParallel(group);
}
return group;
}
private SequentialGroup createSequentialGroup(GroupLayout layout) {
SequentialGroup group = layout.createSequentialGroup();
group.addContainerGap();
boolean first = true;
for (UserVariable variable: variablesToQuery) {
if (!first) {
group.addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED);
}
first = false;
variable.addToSequential(group);
}
group.addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE);
return group;
}
private JPanel createQueryPanel() {
JPanel panel = new JPanel();
GroupLayout layout = new GroupLayout(panel);
panel.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(createParallelGroup(layout))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(createSequentialGroup(layout))
);
return panel;
}
public static Map<DisplayedTaskVariable, String> queryVariables(
Collection<DisplayedTaskVariable> variablesToQuery) {
TaskVariableQueryDialog dlg = new TaskVariableQueryDialog(variablesToQuery);
return dlg.queryVariables();
}
private Map<DisplayedTaskVariable, String> queryVariables() {
if (variablesToQuery.isEmpty()) {
return Collections.emptyMap();
}
getContentPane().removeAll();
JPanel queryPanel = createQueryPanel();
JPanel buttonPanel = new JPanel(new FlowLayout());
JButton okButton = new JButton(NbStrings.getOkOption());
JButton cancelButton = new JButton(NbStrings.getCancelOption());
buttonPanel.add(okButton);
buttonPanel.add(cancelButton);
getRootPane().setDefaultButton(okButton);
final AtomicBoolean okPressed = new AtomicBoolean(false);
okButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
okPressed.set(true);
dispose();
}
});
cancelButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
dispose();
}
});
GroupLayout layout = new GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(queryPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(buttonPanel, GroupLayout.Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(queryPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addComponent(buttonPanel, GroupLayout.PREFERRED_SIZE, 33, GroupLayout.PREFERRED_SIZE))
);
setTitle(NbStrings.getTaskVariableQueryCaption());
pack();
setLocationRelativeTo(null);
setVisible(true);
if (!okPressed.get()) {
return null;
}
Map<DisplayedTaskVariable, String> result = new HashMap<>();
for (UserVariable variable: variablesToQuery) {
result.put(variable.getDisplayedVariable(), variable.getValue());
}
return result;
}
private static final class BoolVariable implements UserVariable {
public static final UserVariableFactory FACTORY = new UserVariableFactory() {
@Override
public UserVariable createVariable(DisplayedTaskVariable variable) {
return new BoolVariable(variable);
}
};
private final DisplayedTaskVariable variable;
private final JCheckBox checkBox;
private final String[] possibleValues;
public BoolVariable(DisplayedTaskVariable variable) {
ExceptionHelper.checkNotNullArgument(variable, "variable");
this.variable = variable;
this.checkBox = new JCheckBox(variable.getDisplayName());
String typeArguments = variable.getTypeDescription().getEscapedTypeArguments();
this.possibleValues = parsePossibleValues(typeArguments, checkBox);
}
private static String[] parsePossibleValues(String valuesStr, JCheckBox checkbox) {
String[] values = StringUtils.unescapedSplit(valuesStr, ',', 2);
if (values.length < 2) {
return new String[]{Boolean.FALSE.toString(), Boolean.TRUE.toString()};
}
for (int i = 0; i < 2; i++) {
values[i] = values[i].trim();
if (values[i].startsWith("*")) {
values[i] = values[i].substring(1).trim();
checkbox.setSelected(i != 0);
}
values[i] = StringUtils.unescapeString(values[i]);
}
return values;
}
@Override
public DisplayedTaskVariable getDisplayedVariable() {
return variable;
}
@Override
public void addToSequential(SequentialGroup group) {
group.addComponent(checkBox);
}
@Override
public void addToParallel(ParallelGroup group) {
group.addComponent(checkBox);
}
@Override
public String getValue() {
return checkBox.isSelected()
? possibleValues[1]
: possibleValues[0];
}
}
private static final class EnumVariable implements UserVariable {
public static final UserVariableFactory FACTORY = new UserVariableFactory() {
@Override
public UserVariable createVariable(DisplayedTaskVariable variable) {
return new EnumVariable(variable);
}
};
private final DisplayedTaskVariable variable;
private final JLabel label;
private final JComboBox<ComboValue> value;
public EnumVariable(DisplayedTaskVariable variable) {
ExceptionHelper.checkNotNullArgument(variable, "variable");
this.variable = variable;
this.label = new JLabel(variable.getDisplayName());
this.value = new JComboBox<>();
parseComboValues(variable.getTypeDescription().getEscapedTypeArguments(), value);
}
private static void parseComboValues(String valuesDef, JComboBox<ComboValue> combo) {
String[] values = StringUtils.unescapedSplit(valuesDef, ',');
ComboValue[] comboValues = new ComboValue[values.length];
int selectedIndex = 0;
for (int i = 0; i < values.length; i++) {
String valueDef = values[i].trim();
if (valueDef.startsWith("*")) {
valueDef = valueDef.substring(1).trim();
selectedIndex = i;
}
comboValues[i] = parseComboValue(valueDef);
}
ComboValue selected = comboValues[selectedIndex];
Arrays.sort(comboValues, new Comparator<ComboValue>() {
@Override
public int compare(ComboValue o1, ComboValue o2) {
return StringUtils.STR_CMP.compare(o1.displayValue, o2.displayValue);
}
});
combo.setModel(new DefaultComboBoxModel<>(comboValues));
combo.setSelectedItem(selected);
}
private static ComboValue parseComboValue(String valueDef) {
String[] valueAndDisplay = StringUtils.unescapedSplit(valueDef, ':', 2);
for (int i = 0; i < valueAndDisplay.length; i++) {
valueAndDisplay[i] = StringUtils.unescapeString(valueAndDisplay[i]).trim();
}
String value = valueAndDisplay[0];
String displayValue = valueAndDisplay.length < 2
? value
: valueAndDisplay[1];
return new ComboValue(value, displayValue);
}
@Override
public DisplayedTaskVariable getDisplayedVariable() {
return variable;
}
@Override
public void addToSequential(SequentialGroup group) {
group.addComponent(label);
group.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED);
group.addComponent(value, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE);
}
@Override
public void addToParallel(ParallelGroup group) {
group.addComponent(label);
group.addComponent(value);
}
@Override
public String getValue() {
ComboValue selected = (ComboValue)value.getSelectedItem();
return selected != null ? selected.value : "";
}
}
private static final class StringVariable implements UserVariable {
public static final UserVariableFactory FACTORY = new UserVariableFactory() {
@Override
public UserVariable createVariable(DisplayedTaskVariable variable) {
return new StringVariable(variable);
}
};
private final DisplayedTaskVariable variable;
private final JLabel label;
private final JTextField value;
public StringVariable(DisplayedTaskVariable variable) {
ExceptionHelper.checkNotNullArgument(variable, "variable");
this.variable = variable;
this.label = new JLabel(variable.getDisplayName());
String typeArguments = variable.getTypeDescription().getEscapedTypeArguments();
this.value = new JTextField(StringUtils.unescapeString(typeArguments));
}
@Override
public DisplayedTaskVariable getDisplayedVariable() {
return variable;
}
@Override
public void addToSequential(SequentialGroup group) {
group.addComponent(label);
group.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED);
group.addComponent(value, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE);
}
@Override
public void addToParallel(ParallelGroup group) {
group.addComponent(label);
group.addComponent(value);
}
@Override
public String getValue() {
return value.getText().trim();
}
}
private interface UserVariable {
public DisplayedTaskVariable getDisplayedVariable();
public void addToSequential(SequentialGroup group);
public void addToParallel(ParallelGroup group);
public String getValue();
}
private interface UserVariableFactory {
public UserVariable createVariable(DisplayedTaskVariable variable);
}
private static final class ComboValue {
public final String value;
public final String displayValue;
public ComboValue(String value, String displayValue) {
this.value = value;
this.displayValue = displayValue;
}
@Override
public String toString() {
return displayValue;
}
}
}