package org.netbeans.gradle.project.properties.ui;
import java.awt.Component;
import java.awt.Container;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JViewport;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.jtrim.utils.ExceptionHelper;
import org.netbeans.gradle.model.util.CollectionUtils;
import org.netbeans.gradle.project.NbGradleProject;
import org.netbeans.gradle.project.NbStrings;
import org.netbeans.gradle.project.api.config.ActiveSettingsQuery;
import org.netbeans.gradle.project.api.config.PropertyReference;
import org.netbeans.gradle.project.api.config.ui.CustomizerCategoryId;
import org.netbeans.gradle.project.api.config.ui.ProfileBasedSettingsCategory;
import org.netbeans.gradle.project.api.config.ui.ProfileBasedSettingsPage;
import org.netbeans.gradle.project.api.config.ui.ProfileBasedSettingsPageFactory;
import org.netbeans.gradle.project.api.config.ui.ProfileEditor;
import org.netbeans.gradle.project.api.config.ui.ProfileEditorFactory;
import org.netbeans.gradle.project.api.config.ui.ProfileInfo;
import org.netbeans.gradle.project.api.config.ui.StoredSettings;
import org.netbeans.gradle.project.properties.NbGradleCommonProperties;
import org.netbeans.gradle.project.properties.PredefinedTask;
import org.netbeans.gradle.project.properties.standard.BuiltInTasks;
import org.netbeans.gradle.project.properties.standard.BuiltInTasksProperty;
import org.netbeans.gradle.project.properties.standard.PredefinedTasks;
import org.netbeans.gradle.project.tasks.DefaultBuiltInTasks;
import org.netbeans.gradle.project.util.NbSupplier;
import org.netbeans.gradle.project.util.StringUtils;
import org.netbeans.gradle.project.view.CustomActionPanel;
@SuppressWarnings("serial")
public class ManageBuiltInTasksPanel extends javax.swing.JPanel implements ProfileEditorFactory {
private static final Logger LOGGER = Logger.getLogger(ManageBuiltInTasksPanel.class.getName());
private static final CustomizerCategoryId CATEGORY_ID = new CustomizerCategoryId(
ManageBuiltInTasksPanel.class.getName() + ".settings",
NbStrings.getManageBuiltInTasksTitle());
private final NbGradleProject project;
private final CustomActionPanel jActionPanel;
private BuiltInTaskItem lastShownItem;
private final Map<String, SavedTask> toSaveTasks;
private PropertyRefs currentEditor;
private ManageBuiltInTasksPanel(NbGradleProject project) {
this.project = project;
this.lastShownItem = null;
this.toSaveTasks = new HashMap<>();
this.currentEditor = null;
initComponents();
jActionPanel = new CustomActionPanel();
jTaskConfigHolder.add(jActionPanel);
jInheritCheck.getModel().addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
setEnabledDisabledState();
}
});
fillTaskCombo();
jTaskCombo.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
showSelectedItem();
}
}
});
showSelectedItem();
}
public static ProfileBasedSettingsCategory createSettingsCategory(final NbGradleProject project) {
ExceptionHelper.checkNotNullArgument(project, "project");
return new ProfileBasedSettingsCategory(CATEGORY_ID, new ProfileBasedSettingsPageFactory() {
@Override
public ProfileBasedSettingsPage createSettingsPage() {
return ManageBuiltInTasksPanel.createSettingsPage(project);
}
});
}
public static ProfileBasedSettingsPage createSettingsPage(NbGradleProject project) {
ManageBuiltInTasksPanel result = new ManageBuiltInTasksPanel(project);
return new ProfileBasedSettingsPage(result, result);
}
@Override
public ProfileEditor startEditingProfile(ProfileInfo profileInfo, ActiveSettingsQuery profileQuery) {
return new PropertyRefs(project, profileQuery);
}
private void setEnableChildrenRecursive(Component component, boolean enabled) {
if (component instanceof Container) {
for (Component subComponent: ((Container)component).getComponents()) {
if (subComponent instanceof JPanel
|| subComponent instanceof JScrollPane
|| subComponent instanceof JViewport) {
setEnableChildrenRecursive(subComponent, enabled);
}
else {
subComponent.setEnabled(enabled);
}
}
}
}
private void setEnabledDisabledState() {
setEnableChildrenRecursive(jActionPanel, !jInheritCheck.isSelected());
}
private String getDisplayNameOfCommand(String command) {
return DefaultBuiltInTasks.getDisplayNameOfCommand(project, command);
}
private void fillTaskCombo() {
Set<String> commands = project.getMergedCommandQuery().getSupportedCommands();
List<BuiltInTaskItem> items = new ArrayList<>(commands.size());
for (String command: commands) {
items.add(new BuiltInTaskItem(command, getDisplayNameOfCommand(command)));
}
Collections.sort(items, new Comparator<BuiltInTaskItem>() {
@Override
public int compare(BuiltInTaskItem o1, BuiltInTaskItem o2) {
return StringUtils.STR_CMP.compare(o1.getDisplayName(), o2.getDisplayName());
}
});
jTaskCombo.setModel(new DefaultComboBoxModel<>(items.toArray(new BuiltInTaskItem[items.size()])));
jTaskCombo.getModel().setSelectedItem(items.get(0));
}
private BuiltInTaskItem getSelectedItem() {
Object selected = jTaskCombo.getSelectedItem();
if (selected instanceof BuiltInTaskItem) {
return (BuiltInTaskItem)selected;
}
if (selected == null) {
LOGGER.warning("There is no selected built-in task.");
}
else {
LOGGER.log(Level.WARNING, "Task combo contains item with invalid type: {0}", selected.getClass().getName());
}
return null;
}
private PropertyReference<BuiltInTasks> tryGetPropertyRef() {
return currentEditor != null ? currentEditor.builtInTasksRef : null;
}
private PredefinedTask tryGetValueWithoutFallback(BuiltInTaskItem item) {
PropertyReference<BuiltInTasks> propertyRef = tryGetPropertyRef();
if (item == null || propertyRef == null) {
return null;
}
BuiltInTasks builtInTasks = propertyRef.tryGetValueWithoutFallback();
return builtInTasks != null ? builtInTasks.tryGetByCommand(item.command) : null;
}
private PredefinedTask tryGetActiveValue(BuiltInTaskItem item) {
PropertyReference<BuiltInTasks> propertyRef = tryGetPropertyRef();
if (item == null || propertyRef == null) {
return null;
}
BuiltInTasks builtInTasks = propertyRef.getActiveValue();
return builtInTasks != null ? builtInTasks.tryGetByCommand(item.command) : null;
}
private PredefinedTask getCurrentValue(String command) {
PropertyReference<BuiltInTasks> propertyRef = tryGetPropertyRef();
BuiltInTasks builtInTasks = propertyRef != null ? propertyRef.getActiveValue() : null;
PredefinedTask result = builtInTasks != null ? builtInTasks.tryGetByCommand(command) : null;
if (result == null) {
result = new PredefinedTask(command,
Arrays.asList(new PredefinedTask.Name("tasks", false)),
Collections.<String>emptyList(),
Collections.<String>emptyList(),
true);
}
return result;
}
private SavedTask getLastShownTask() {
if (lastShownItem == null) {
return null;
}
final String command = lastShownItem.getCommand();
jActionPanel.setTasksMustExist(false);
PredefinedTask resultTask = jActionPanel.tryGetPredefinedTask(command, new NbSupplier<List<PredefinedTask.Name>>() {
@Override
public List<PredefinedTask.Name> get() {
SavedTask lastValue = toSaveTasks.get(command);
if (lastValue == null) {
return getCurrentValue(command).getTaskNames();
}
else {
return lastValue.getTaskDef().getTaskNames();
}
}
});
return resultTask != null ? new SavedTask(resultTask, jInheritCheck.isSelected()) : null;
}
private void saveLastShown() {
SavedTask lastShownTask = getLastShownTask();
if (lastShownTask == null) {
return;
}
toSaveTasks.put(lastShownTask.getCommand(), lastShownTask);
}
private void showSelectedItem() {
BuiltInTaskItem selectedItem = getSelectedItem();
if (selectedItem == null) {
return;
}
PredefinedTask task;
boolean defaultValue;
SavedTask savedTask = toSaveTasks.get(selectedItem.getCommand());
if (savedTask != null) {
task = savedTask.getTaskDef();
defaultValue = savedTask.isInherited();
}
else {
task = tryGetActiveValue(selectedItem);
defaultValue = tryGetValueWithoutFallback(selectedItem) == null;
}
if (task == null) {
return;
}
saveLastShown();
lastShownItem = null;
jActionPanel.updatePanel(task);
jInheritCheck.setSelected(defaultValue);
lastShownItem = selectedItem;
setEnabledDisabledState();
}
private final class PropertyRefs implements ProfileEditor {
private final PropertyReference<BuiltInTasks> builtInTasksRef;
public PropertyRefs(NbGradleProject ownerProject, ActiveSettingsQuery settingsQuery) {
this.builtInTasksRef = NbGradleCommonProperties.builtInTasks(ownerProject, settingsQuery);
}
@Override
public StoredSettings readFromSettings() {
return new StoredSettingsImpl(this);
}
@Override
public StoredSettings readFromGui() {
return new StoredSettingsImpl(this, ManageBuiltInTasksPanel.this);
}
}
private final class StoredSettingsImpl implements StoredSettings {
private final PropertyRefs properties;
private final Map<String, SavedTask> modifiedCommands;
public StoredSettingsImpl(PropertyRefs properties) {
this.properties = properties;
this.modifiedCommands = new HashMap<>();
}
public StoredSettingsImpl(PropertyRefs properties, ManageBuiltInTasksPanel panel) {
this.properties = properties;
panel.saveLastShown();
this.modifiedCommands = new HashMap<>(panel.toSaveTasks);
}
@Override
public void displaySettings() {
ManageBuiltInTasksPanel.this.currentEditor = properties;
toSaveTasks.clear();
toSaveTasks.putAll(modifiedCommands);
showSelectedItem();
}
@Override
public void saveSettings() {
PropertyReference<BuiltInTasks> builtInTasksRef = properties.builtInTasksRef;
BuiltInTasks currentTasks = builtInTasksRef.tryGetValueWithoutFallback();
PredefinedTasks currentTaskList = currentTasks != null
? currentTasks.getAllTasks()
: PredefinedTasks.NO_TASKS;
Map<String, PredefinedTask> taskMap = CollectionUtils.newLinkedHashMap(currentTaskList.getTasks().size());
for (PredefinedTask task: currentTaskList.getTasks()) {
String command = task.getDisplayName();
taskMap.put(command, task);
}
for (SavedTask task: modifiedCommands.values()) {
if (task.isInherited()) {
taskMap.remove(task.getCommand());
}
else {
taskMap.put(task.getCommand(), task.getTaskDef());
}
}
builtInTasksRef.setValue(BuiltInTasksProperty.createValue(taskMap.values()));
}
}
private static class SavedTask {
private final PredefinedTask taskDef;
private final boolean inherited;
public SavedTask(PredefinedTask taskDef, boolean inherited) {
assert taskDef != null;
this.taskDef = taskDef;
this.inherited = inherited;
}
public String getCommand() {
return taskDef.getDisplayName();
}
public PredefinedTask getTaskDef() {
return taskDef;
}
public boolean isInherited() {
return inherited;
}
}
private static class BuiltInTaskItem {
private final String command;
private final String displayName;
public BuiltInTaskItem(String command, String displayName) {
assert command != null;
assert displayName != null;
this.command = command;
this.displayName = displayName;
}
public String getCommand() {
return command;
}
public String getDisplayName() {
return displayName;
}
@Override
public int hashCode() {
int hash = 5;
hash = 79 * hash + Objects.hashCode(command);
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
final BuiltInTaskItem other = (BuiltInTaskItem)obj;
return Objects.equals(this.command, other.command);
}
@Override
public String toString() {
return displayName;
}
}
/**
* 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() {
jTaskCombo = new javax.swing.JComboBox<>();
jInheritCheck = new javax.swing.JCheckBox();
jTaskConfigHolder = new javax.swing.JPanel();
org.openide.awt.Mnemonics.setLocalizedText(jInheritCheck, org.openide.util.NbBundle.getMessage(ManageBuiltInTasksPanel.class, "ManageBuiltInTasksPanel.jInheritCheck.text")); // NOI18N
jTaskConfigHolder.setLayout(new java.awt.GridLayout(1, 1));
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()
.addComponent(jTaskCombo, 0, 321, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jInheritCheck)
.addContainerGap())
.addComponent(jTaskConfigHolder, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jTaskCombo, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jInheritCheck))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jTaskConfigHolder, javax.swing.GroupLayout.DEFAULT_SIZE, 258, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JCheckBox jInheritCheck;
private javax.swing.JComboBox<BuiltInTaskItem> jTaskCombo;
private javax.swing.JPanel jTaskConfigHolder;
// End of variables declaration//GEN-END:variables
}