IDEA-103464 Adding environment variables to a Tomcat server is a UX nightmare
[idea/community.git] / platform / lang-api / src / com / intellij / execution / util / ListTableWithButtons.java
1 /*
2  * Copyright 2000-2014 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.execution.util;
17
18 import com.intellij.openapi.actionSystem.AnActionEvent;
19 import com.intellij.ui.AnActionButton;
20 import com.intellij.ui.AnActionButtonRunnable;
21 import com.intellij.ui.AnActionButtonUpdater;
22 import com.intellij.ui.ToolbarDecorator;
23 import com.intellij.ui.table.TableView;
24 import com.intellij.util.containers.ContainerUtil;
25 import com.intellij.util.ui.ColumnInfo;
26 import com.intellij.util.ui.ListTableModel;
27 import org.jetbrains.annotations.Nullable;
28
29 import javax.swing.*;
30 import javax.swing.table.DefaultTableCellRenderer;
31 import javax.swing.table.TableCellRenderer;
32 import java.awt.event.KeyAdapter;
33 import java.awt.event.KeyEvent;
34 import java.util.List;
35 import java.util.Observable;
36
37 /**
38  * @author traff
39  */
40 public abstract class ListTableWithButtons<T> extends Observable {
41   private final List<T> myElements = ContainerUtil.newArrayList();
42   private final JPanel myPanel;
43   private final TableView<T> myTableView;
44   private boolean myIsEnabled = true;
45
46   protected ListTableWithButtons() {
47     myTableView = new TableView(createListModel()) {
48       @Override
49       protected void createDefaultEditors() {
50         super.createDefaultEditors();
51         Object editor = defaultEditorsByColumnClass.get(String.class);
52         if (editor instanceof DefaultCellEditor) {
53           ((DefaultCellEditor)editor).getComponent().addKeyListener(new KeyAdapter() {
54             @Override
55             public void keyPressed(KeyEvent e) {
56               final int column = myTableView.getEditingColumn();
57               final int row = myTableView.getEditingRow();
58               if (e.getModifiers() == 0 && (e.getKeyCode() == KeyEvent.VK_ENTER || e.getKeyCode() == KeyEvent.VK_TAB)) {
59                 SwingUtilities.invokeLater(new Runnable() {
60                   @Override
61                   public void run() {
62                     stopEditing();
63                     int nextColumn = column < myTableView.getColumnCount() - 1? column + 1 : 0;
64                     int nextRow = nextColumn == 0 ? row + 1 : row;
65                     if (nextRow > myTableView.getRowCount() - 1) {
66                       if (myElements.isEmpty() || !ListTableWithButtons.this.isEmpty(myElements.get(myElements.size() - 1))) {
67                         ToolbarDecorator.findAddButton(myPanel).actionPerformed(null);
68                         return;
69                       } else {
70                         nextRow = 0;
71                       }
72                     }
73                     myTableView.editCellAt(nextRow, nextColumn);
74                   }
75                 });
76               }
77             }
78           });
79         }
80       }
81     };
82     myTableView.setRowHeight(new JTextField().getPreferredSize().height);
83     myTableView.getTableViewModel().setSortable(false);
84     myPanel = ToolbarDecorator.createDecorator(myTableView)
85       .setAddAction(new AnActionButtonRunnable() {
86         @Override
87         public void run(AnActionButton button) {
88           if (!myElements.isEmpty() && isEmpty(myElements.get(myElements.size() - 1))) return;
89           myTableView.stopEditing();
90           setModified();
91           SwingUtilities.invokeLater(new Runnable() {
92             @Override
93             public void run() {
94               myElements.add(createElement());
95               myTableView.getTableViewModel().setItems(myElements);
96               myTableView.scrollRectToVisible(myTableView.getCellRect(myElements.size() - 1, 0, true));
97               myTableView.getComponent().editCellAt(myElements.size() - 1, 0);
98             }
99           });
100         }
101       }).setRemoveAction(new AnActionButtonRunnable() {
102         @Override
103         public void run(AnActionButton button) {
104           myTableView.stopEditing();
105           setModified();
106           T selected = getSelection();
107           if (selected != null) {
108             int selectedIndex = myElements.indexOf(selected);
109             myElements.remove(selected);
110             myTableView.getTableViewModel().setItems(myElements);
111
112             int prev = selectedIndex - 1;
113             if (prev >= 0) {
114               myTableView.getComponent().getSelectionModel().setSelectionInterval(prev, prev);
115             }
116             else if (selectedIndex < myElements.size()) {
117               myTableView.getComponent().getSelectionModel().setSelectionInterval(selectedIndex, selectedIndex);
118             }
119           }
120         }
121       }).disableUpDownActions().addExtraActions(createExtraActions()).createPanel();
122
123     ToolbarDecorator.findRemoveButton(myPanel).addCustomUpdater(new AnActionButtonUpdater() {
124       @Override
125       public boolean isEnabled(AnActionEvent e) {
126         T selection = getSelection();
127         return selection != null && myIsEnabled && canDeleteElement(selection);
128       }
129     });
130     ToolbarDecorator.findAddButton(myPanel).addCustomUpdater(new AnActionButtonUpdater() {
131       @Override
132       public boolean isEnabled(AnActionEvent e) {
133         return myIsEnabled;
134       }
135     });
136
137
138     myTableView.getComponent().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
139   }
140
141   protected abstract ListTableModel createListModel();
142
143   protected void setModified() {
144     setChanged();
145     notifyObservers();
146   }
147
148   protected List<T> getElements() {
149     return myElements;
150   }
151
152   public JComponent getComponent() {
153     return myPanel;
154   }
155
156   public void setEnabled() {
157     myTableView.getComponent().setEnabled(true);
158     myIsEnabled = true;
159   }
160
161   public void setDisabled() {
162     myTableView.getComponent().setEnabled(false);
163     myIsEnabled = false;
164   }
165
166   public void stopEditing() {
167     myTableView.stopEditing();
168   }
169
170   public void refreshValues() {
171     myTableView.getComponent().repaint();
172   }
173
174   protected abstract T createElement();
175
176   protected abstract boolean isEmpty(T element);
177
178   protected AnActionButton[] createExtraActions() {
179     return null;
180   }
181
182
183   protected T getSelection() {
184     int selIndex = myTableView.getComponent().getSelectionModel().getMinSelectionIndex();
185     if (selIndex < 0) {
186       return null;
187     }
188     else {
189       return myElements.get(selIndex);
190     }
191   }
192
193   public void setValues(List<T> envVariables) {
194     myElements.clear();
195     for (T envVariable : envVariables) {
196       myElements.add(cloneElement(envVariable));
197     }
198     myTableView.getTableViewModel().setItems(myElements);
199   }
200
201   protected abstract T cloneElement(T variable);
202
203   protected abstract boolean canDeleteElement(T selection);
204
205   protected static abstract class ElementsColumnInfoBase<T> extends ColumnInfo<T, String> {
206     private DefaultTableCellRenderer myRenderer;
207
208     protected ElementsColumnInfoBase(String name) {
209       super(name);
210     }
211
212     @Override
213     public TableCellRenderer getRenderer(T element) {
214       if (myRenderer == null) {
215         myRenderer = new DefaultTableCellRenderer();
216       }
217       if (element != null) {
218         myRenderer.setText(valueOf(element));
219         myRenderer.setToolTipText(getDescription(element));
220       }
221       return myRenderer;
222     }
223
224     @Nullable
225     protected abstract String getDescription(T element);
226   }
227 }