IDEA-103464 Adding environment variables to a Tomcat server is a UX nightmare

This commit is contained in:
Vassiliy.Kudryashov
2014-11-03 15:31:00 +03:00
parent 88b3ecdc6f
commit 00b643ab5d
7 changed files with 144 additions and 8 deletions
@@ -16,10 +16,22 @@
package com.intellij.execution.util;
import com.intellij.icons.AllIcons;
import com.intellij.idea.ActionsBundle;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.ide.CopyPasteManager;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.AnActionButton;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.ColumnInfo;
import com.intellij.util.ui.ListTableModel;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.util.ArrayList;
import java.util.List;
public class EnvVariablesTable extends ListTableWithButtons<EnvironmentVariable> {
@@ -91,6 +103,61 @@ public class EnvVariablesTable extends ListTableWithButtons<EnvironmentVariable>
return new EnvironmentVariable("", "", false);
}
@Override
protected boolean isEmpty(EnvironmentVariable element) {
return element.getName().isEmpty() && element.getValue().isEmpty();
}
@Override
protected AnActionButton[] createExtraActions() {
AnActionButton copyButton = new AnActionButton(ActionsBundle.message("action.EditorCopy.text"), AllIcons.Actions.Copy) {
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
stopEditing();
StringBuilder sb = new StringBuilder();
List<EnvironmentVariable> variables = getEnvironmentVariables();
for (EnvironmentVariable environmentVariable : variables) {
if (environmentVariable.getIsPredefined() || isEmpty(environmentVariable)) continue;
if (sb.length() > 0) sb.append('\n');
sb.append(StringUtil.escapeChar(environmentVariable.getName(), '=')).append('=')
.append(StringUtil.escapeChar(environmentVariable.getValue(), '='));
}
CopyPasteManager.getInstance().setContents(new StringSelection(sb.toString()));
}
};
AnActionButton pasteButton = new AnActionButton(ActionsBundle.message("action.EditorPaste.text"), AllIcons.Actions.Menu_paste) {
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
stopEditing();
String content = CopyPasteManager.getInstance().getContents(DataFlavor.stringFlavor);
if (content == null || !content.contains("=")) return;
List<EnvironmentVariable> parsed = new ArrayList<EnvironmentVariable>();
List<String> lines = StringUtil.split(content, "\n");
for (String line : lines) {
int pos = line.indexOf('=');
if (pos == -1) continue;
while (pos > 0 && line.charAt(pos - 1) == '\\') {
pos = line.indexOf('=', pos + 1);
}
parsed.add(new EnvironmentVariable(
StringUtil.unescapeStringCharacters(line.substring(0, pos)),
StringUtil.unescapeStringCharacters(line.substring(pos + 1)),
false));
}
List<EnvironmentVariable> variables =
new ArrayList<EnvironmentVariable>(ContainerUtil.filter(getEnvironmentVariables(), new Condition<EnvironmentVariable>() {
@Override
public boolean value(EnvironmentVariable variable) {
return variable.getIsPredefined();
}
}));
variables.addAll(parsed);
setValues(variables);
}
};
return new AnActionButton[]{copyButton, pasteButton};
}
@Override
protected EnvironmentVariable cloneElement(EnvironmentVariable envVariable) {
return envVariable.clone();
@@ -29,6 +29,8 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.List;
import java.util.Observable;
@@ -38,17 +40,52 @@ import java.util.Observable;
public abstract class ListTableWithButtons<T> extends Observable {
private final List<T> myElements = ContainerUtil.newArrayList();
private final JPanel myPanel;
private final TableView myTableView;
private final TableView<T> myTableView;
private boolean myIsEnabled = true;
protected ListTableWithButtons() {
myTableView = new TableView(createListModel());
myTableView = new TableView(createListModel()) {
@Override
protected void createDefaultEditors() {
super.createDefaultEditors();
Object editor = defaultEditorsByColumnClass.get(String.class);
if (editor instanceof DefaultCellEditor) {
((DefaultCellEditor)editor).getComponent().addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
final int column = myTableView.getEditingColumn();
final int row = myTableView.getEditingRow();
if (e.getModifiers() == 0 && (e.getKeyCode() == KeyEvent.VK_ENTER || e.getKeyCode() == KeyEvent.VK_TAB)) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
stopEditing();
int nextColumn = column < myTableView.getColumnCount() - 1? column + 1 : 0;
int nextRow = nextColumn == 0 ? row + 1 : row;
if (nextRow > myTableView.getRowCount() - 1) {
if (myElements.isEmpty() || !ListTableWithButtons.this.isEmpty(myElements.get(myElements.size() - 1))) {
ToolbarDecorator.findAddButton(myPanel).actionPerformed(null);
return;
} else {
nextRow = 0;
}
}
myTableView.editCellAt(nextRow, nextColumn);
}
});
}
}
});
}
}
};
myTableView.setRowHeight(new JTextField().getPreferredSize().height);
myTableView.getTableViewModel().setSortable(false);
myPanel = ToolbarDecorator.createDecorator(myTableView)
.setAddAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton button) {
if (!myElements.isEmpty() && isEmpty(myElements.get(myElements.size() - 1))) return;
myTableView.stopEditing();
setModified();
SwingUtilities.invokeLater(new Runnable() {
@@ -56,6 +93,7 @@ public abstract class ListTableWithButtons<T> extends Observable {
public void run() {
myElements.add(createElement());
myTableView.getTableViewModel().setItems(myElements);
myTableView.scrollRectToVisible(myTableView.getCellRect(myElements.size() - 1, 0, true));
myTableView.getComponent().editCellAt(myElements.size() - 1, 0);
}
});
@@ -65,7 +103,7 @@ public abstract class ListTableWithButtons<T> extends Observable {
public void run(AnActionButton button) {
myTableView.stopEditing();
setModified();
Object selected = getSelection();
T selected = getSelection();
if (selected != null) {
int selectedIndex = myElements.indexOf(selected);
myElements.remove(selected);
@@ -80,7 +118,7 @@ public abstract class ListTableWithButtons<T> extends Observable {
}
}
}
}).disableUpDownActions().createPanel();
}).disableUpDownActions().addExtraActions(createExtraActions()).createPanel();
ToolbarDecorator.findRemoveButton(myPanel).addCustomUpdater(new AnActionButtonUpdater() {
@Override
@@ -135,6 +173,12 @@ public abstract class ListTableWithButtons<T> extends Observable {
protected abstract T createElement();
protected abstract boolean isEmpty(T element);
protected AnActionButton[] createExtraActions() {
return null;
}
protected T getSelection() {
int selIndex = myTableView.getComponent().getSelectionModel().getMinSelectionIndex();
@@ -88,6 +88,11 @@ final class PathMappingTable extends ListTableWithButtons<PathMappingSettings.Pa
return new PathMappingSettings.PathMapping();
}
@Override
protected boolean isEmpty(PathMappingSettings.PathMapping element) {
return element.getLocalRoot().isEmpty() && element.getRemoteRoot().isEmpty();
}
@Override
protected PathMappingSettings.PathMapping cloneElement(PathMappingSettings.PathMapping envVariable) {
return envVariable.clone();
@@ -191,7 +191,16 @@ public abstract class ToolbarDecorator implements CommonActionsPanel.ListenerFac
}
public ToolbarDecorator addExtraAction(AnActionButton action) {
myExtraActions.add(action);
if (action != null) {
myExtraActions.add(action);
}
return this;
}
public ToolbarDecorator addExtraActions(AnActionButton... actions) {
for (AnActionButton action : actions) {
addExtraAction(action);
}
return this;
}
@@ -258,7 +258,7 @@ public class TableView<Item> extends BaseTableView implements ItemsProvider, Sel
return this;
}
public TableViewModel getTableViewModel() {
public TableViewModel<Item> getTableViewModel() {
return getListTableModel();
}
@@ -274,7 +274,9 @@ public class TableView<Item> extends BaseTableView implements ItemsProvider, Sel
defaultEditorsByColumnClass.put(String.class, new UIDefaults.LazyValue() {
@Override
public Object createValue(UIDefaults table) {
return new DefaultCellEditor(GuiUtils.createUndoableTextField());
DefaultCellEditor editor = new DefaultCellEditor(GuiUtils.createUndoableTextField());
editor.setClickCountToStart(1);
return editor;
}
});
}
@@ -23,7 +23,6 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.packaging.artifacts.Artifact;
import com.intellij.packaging.ui.ArtifactPropertiesEditor;
@@ -316,6 +315,11 @@ public class JavaFxArtifactPropertiesEditor extends ArtifactPropertiesEditor {
return new JavaFxManifestAttribute("", "");
}
@Override
protected boolean isEmpty(JavaFxManifestAttribute element) {
return element.getName().isEmpty() && element.getValue().isEmpty();
}
@Override
protected JavaFxManifestAttribute cloneElement(JavaFxManifestAttribute attribute) {
return new JavaFxManifestAttribute(attribute.getName(), attribute.getValue());
@@ -206,6 +206,11 @@ public class ManageTemplateVariablesDialog extends DialogWrapper {
return new TemplateVariable("", "");
}
@Override
protected boolean isEmpty(TemplateVariable element) {
return element.getName().isEmpty() && element.getValue().isEmpty();
}
@Override
protected TemplateVariable cloneElement(final TemplateVariable variable) {
return variable.clone();