2 * Copyright 2000-2009 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com
.intellij
.refactoring
.util
;
18 import com
.intellij
.openapi
.project
.Project
;
19 import com
.intellij
.psi
.*;
20 import com
.intellij
.refactoring
.ui
.TypeSelector
;
21 import com
.intellij
.refactoring
.ui
.TypeSelectorManager
;
22 import com
.intellij
.refactoring
.ui
.TypeSelectorManagerImpl
;
23 import com
.intellij
.ui
.BooleanTableCellRenderer
;
24 import com
.intellij
.ui
.ScrollPaneFactory
;
25 import com
.intellij
.ui
.TableUtil
;
26 import com
.intellij
.ui
.UIBundle
;
27 import com
.intellij
.util
.ui
.AbstractTableCellEditor
;
28 import com
.intellij
.util
.ui
.Table
;
29 import org
.jetbrains
.annotations
.NonNls
;
32 import javax
.swing
.event
.ListSelectionEvent
;
33 import javax
.swing
.event
.ListSelectionListener
;
34 import javax
.swing
.table
.AbstractTableModel
;
35 import javax
.swing
.table
.DefaultTableCellRenderer
;
36 import javax
.swing
.table
.TableCellEditor
;
38 import java
.awt
.event
.ActionEvent
;
39 import java
.awt
.event
.ActionListener
;
40 import java
.awt
.event
.KeyEvent
;
41 import java
.util
.ArrayList
;
43 public abstract class ParameterTablePanel
extends JPanel
{
44 private final Project myProject
;
45 private final VariableData
[] myVariableData
;
46 private final TypeSelector
[] myParameterTypeSelectors
;
48 private final Table myTable
;
49 private final MyTableModel myTableModel
;
50 private final JButton myUpButton
;
51 private final JButton myDownButton
;
52 private final JComboBox myTypeRendererCombo
;
54 public VariableData
[] getVariableData() {
55 return myVariableData
;
58 public static class VariableData
{
59 public final PsiVariable variable
;
62 public boolean passAsParameter
;
64 public VariableData(PsiVariable var
) {
69 public VariableData(PsiVariable var
, PsiType type
) {
75 protected abstract void updateSignature();
77 protected abstract void doEnterAction();
79 protected abstract void doCancelAction();
81 protected boolean areTypesDirected() {
85 public ParameterTablePanel(Project project
, VariableData
[] variableData
, final PsiElement
... scopeElements
) {
86 super(new BorderLayout());
88 myVariableData
= variableData
;
90 myTableModel
= new MyTableModel();
91 myTable
= new Table(myTableModel
);
92 DefaultCellEditor defaultEditor
= (DefaultCellEditor
)myTable
.getDefaultEditor(Object
.class);
93 defaultEditor
.setClickCountToStart(1);
95 myTable
.setTableHeader(null);
96 myTable
.getSelectionModel().setSelectionMode(ListSelectionModel
.SINGLE_SELECTION
);
97 myTable
.getColumnModel().getColumn(MyTableModel
.CHECKMARK_COLUMN
).setCellRenderer(new CheckBoxTableCellRenderer());
98 myTable
.getColumnModel().getColumn(MyTableModel
.CHECKMARK_COLUMN
).setMaxWidth(new JCheckBox().getPreferredSize().width
);
99 myTable
.getColumnModel().getColumn(MyTableModel
.PARAMETER_NAME_COLUMN
).setCellRenderer(new DefaultTableCellRenderer() {
100 public Component
getTableCellRendererComponent(JTable table
, Object value
, boolean isSelected
, boolean hasFocus
, int row
, int column
) {
101 super.getTableCellRendererComponent(table
, value
, isSelected
, hasFocus
, row
, column
);
102 VariableData data
= getVariableData()[row
];
108 myParameterTypeSelectors
= new TypeSelector
[getVariableData().length
];
109 for (int i
= 0; i
< myParameterTypeSelectors
.length
; i
++) {
110 final PsiExpression
[] occurrences
= findVariableOccurrences(scopeElements
, getVariableData()[i
].variable
);
111 final TypeSelectorManager manager
= new TypeSelectorManagerImpl(myProject
, getVariableData()[i
].type
, occurrences
, areTypesDirected());
112 myParameterTypeSelectors
[i
] = manager
.getTypeSelector();
113 getVariableData()[i
].type
= myParameterTypeSelectors
[i
].getSelectedType(); //reverse order
116 myTypeRendererCombo
= new JComboBox(getVariableData());
117 myTypeRendererCombo
.setOpaque(true);
118 myTypeRendererCombo
.setBorder(null);
120 myTypeRendererCombo
.setRenderer(new DefaultListCellRenderer() {
122 public Component
getListCellRendererComponent(final JList list
,
124 final int index
, final boolean isSelected
, final boolean cellHasFocus
) {
125 setText(((VariableData
)value
).type
.getPresentableText());
130 myTable
.getColumnModel().getColumn(MyTableModel
.PARAMETER_TYPE_COLUMN
).setCellEditor(new AbstractTableCellEditor() {
131 TypeSelector myCurrentSelector
;
132 public Object
getCellEditorValue() {
133 return myCurrentSelector
.getSelectedType();
136 public Component
getTableCellEditorComponent(final JTable table
,
138 final boolean isSelected
,
141 myCurrentSelector
= myParameterTypeSelectors
[row
];
142 return myCurrentSelector
.getComponent();
146 myTable
.getColumnModel().getColumn(MyTableModel
.PARAMETER_TYPE_COLUMN
).setCellRenderer(new DefaultTableCellRenderer() {
147 public Component
getTableCellRendererComponent(JTable table
, Object value
, boolean isSelected
, boolean hasFocus
, int row
, int column
) {
148 if (myParameterTypeSelectors
[row
].getComponent() instanceof JComboBox
) {
149 myTypeRendererCombo
.setSelectedIndex(row
);
150 return myTypeRendererCombo
;
153 super.getTableCellRendererComponent(table
, value
, isSelected
, hasFocus
, row
, column
);
154 VariableData data
= getVariableData()[row
];
155 setText(data
.type
.getPresentableText());
160 myTable
.setPreferredScrollableViewportSize(new Dimension(250, myTable
.getRowHeight() * 5));
161 myTable
.setShowGrid(false);
162 myTable
.setIntercellSpacing(new Dimension(0, 0));
163 @NonNls final InputMap inputMap
= myTable
.getInputMap();
164 inputMap
.put(KeyStroke
.getKeyStroke(KeyEvent
.VK_SPACE
, 0), "enable_disable");
165 @NonNls final ActionMap actionMap
= myTable
.getActionMap();
166 actionMap
.put("enable_disable", new AbstractAction() {
167 public void actionPerformed(ActionEvent e
) {
168 if (myTable
.isEditing()) return;
169 int[] rows
= myTable
.getSelectedRows();
170 if (rows
.length
> 0) {
171 boolean valueToBeSet
= false;
172 for (int row
: rows
) {
173 if (!getVariableData()[row
].passAsParameter
) {
178 for (int row
: rows
) {
179 getVariableData()[row
].passAsParameter
= valueToBeSet
;
181 myTableModel
.fireTableRowsUpdated(rows
[0], rows
[rows
.length
- 1]);
182 TableUtil
.selectRows(myTable
, rows
);
186 // F2 should edit the name
187 inputMap
.put(KeyStroke
.getKeyStroke(KeyEvent
.VK_F2
, 0), "edit_parameter_name");
188 actionMap
.put("edit_parameter_name", new AbstractAction() {
189 public void actionPerformed(ActionEvent e
) {
190 if (!myTable
.isEditing()) {
191 int row
= myTable
.getSelectedRow();
192 if (row
>= 0 && row
< myTableModel
.getRowCount()) {
193 TableUtil
.editCellAt(myTable
, row
, MyTableModel
.PARAMETER_NAME_COLUMN
);
199 // make ENTER work when the table has focus
200 inputMap
.put(KeyStroke
.getKeyStroke(KeyEvent
.VK_ENTER
, 0), "invokeImpl");
201 actionMap
.put("invokeImpl", new AbstractAction() {
202 public void actionPerformed(ActionEvent e
) {
203 TableCellEditor editor
= myTable
.getCellEditor();
204 if (editor
!= null) {
205 editor
.stopCellEditing();
213 // make ESCAPE work when the table has focus
214 actionMap
.put("doCancel", new AbstractAction() {
215 public void actionPerformed(ActionEvent e
) {
216 TableCellEditor editor
= myTable
.getCellEditor();
217 if (editor
!= null) {
218 editor
.stopCellEditing();
226 JPanel listPanel
= new JPanel(new BorderLayout());
227 JScrollPane scrollPane
= ScrollPaneFactory
.createScrollPane(myTable
);
228 listPanel
.add(scrollPane
, BorderLayout
.CENTER
);
229 listPanel
.setBorder(BorderFactory
.createEmptyBorder(4, 4, 4, 4));
230 add(listPanel
, BorderLayout
.CENTER
);
232 JPanel buttonsPanel
= new JPanel();
233 buttonsPanel
.setBorder(BorderFactory
.createEmptyBorder(4, 4, 4, 4));
234 add(buttonsPanel
, BorderLayout
.EAST
);
236 buttonsPanel
.setLayout(new GridBagLayout());
237 GridBagConstraints gbConstraints
= new GridBagConstraints();
238 gbConstraints
.gridwidth
= GridBagConstraints
.REMAINDER
;
239 gbConstraints
.fill
= GridBagConstraints
.HORIZONTAL
;
240 gbConstraints
.insets
= new Insets(2, 4, 2, 4);
242 myUpButton
= new JButton();
243 myUpButton
.setText(UIBundle
.message("row.move.up"));
244 myUpButton
.setDefaultCapable(false);
245 buttonsPanel
.add(myUpButton
, gbConstraints
);
247 myDownButton
= new JButton();
248 myDownButton
.setText(UIBundle
.message("row.move.down"));
249 myDownButton
.setDefaultCapable(false);
250 buttonsPanel
.add(myDownButton
, gbConstraints
);
252 gbConstraints
.weighty
= 1;
253 buttonsPanel
.add(new JPanel(), gbConstraints
);
255 myUpButton
.addActionListener(new ActionListener() {
256 public void actionPerformed(ActionEvent e
) {
257 if (myTable
.isEditing()) {
258 final boolean isStopped
= myTable
.getCellEditor().stopCellEditing();
259 if (!isStopped
) return;
261 moveSelectedItem(-1);
263 myTable
.requestFocus();
267 myDownButton
.addActionListener(new ActionListener() {
268 public void actionPerformed(ActionEvent e
) {
269 if (myTable
.isEditing()) {
270 final boolean isStopped
= myTable
.getCellEditor().stopCellEditing();
271 if (!isStopped
) return;
273 moveSelectedItem(+1);
275 myTable
.requestFocus();
279 myTable
.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
280 public void valueChanged(ListSelectionEvent e
) {
284 if (getVariableData().length
<= 1) {
285 myUpButton
.setEnabled(false);
286 myDownButton
.setEnabled(false);
289 myTable
.getSelectionModel().setSelectionInterval(0, 0);
294 private static PsiExpression
[] findVariableOccurrences(final PsiElement
[] scopeElements
, final PsiVariable variable
) {
295 final ArrayList
<PsiExpression
> result
= new ArrayList
<PsiExpression
>();
296 for (final PsiElement element
: scopeElements
) {
297 element
.accept(new JavaRecursiveElementWalkingVisitor() {
298 @Override public void visitReferenceExpression(final PsiReferenceExpression expression
) {
299 super.visitReferenceExpression(expression
);
300 if (!expression
.isQualified() && expression
.isReferenceTo(variable
)) {
301 result
.add(expression
);
306 return result
.toArray(new PsiExpression
[result
.size()]);
309 private void updateMoveButtons() {
310 int row
= myTable
.getSelectedRow();
311 if (0 <= row
&& row
< getVariableData().length
) {
312 myUpButton
.setEnabled(row
> 0);
313 myDownButton
.setEnabled(row
< getVariableData().length
- 1);
316 myUpButton
.setEnabled(false);
317 myDownButton
.setEnabled(false);
321 private void moveSelectedItem(int moveIncrement
) {
322 int row
= myTable
.getSelectedRow();
323 if (row
< 0 || row
>= getVariableData().length
) return;
324 int targetRow
= row
+ moveIncrement
;
325 if (targetRow
< 0 || targetRow
>= getVariableData().length
) return;
327 VariableData currentItem
= getVariableData()[row
];
328 getVariableData()[row
] = getVariableData()[targetRow
];
329 getVariableData()[targetRow
] = currentItem
;
331 TypeSelector currentSelector
= myParameterTypeSelectors
[row
];
332 myParameterTypeSelectors
[row
] = myParameterTypeSelectors
[targetRow
];
333 myParameterTypeSelectors
[targetRow
] = currentSelector
;
335 myTypeRendererCombo
.setModel(new DefaultComboBoxModel(getVariableData()));
337 myTableModel
.fireTableRowsUpdated(Math
.min(targetRow
, row
), Math
.max(targetRow
, row
));
338 myTable
.getSelectionModel().setSelectionInterval(targetRow
, targetRow
);
341 public void setEnabled(boolean enabled
) {
342 myTable
.setEnabled(enabled
);
344 myUpButton
.setEnabled(false);
345 myDownButton
.setEnabled(false);
350 super.setEnabled(enabled
);
353 private class MyTableModel
extends AbstractTableModel
{
354 public static final int CHECKMARK_COLUMN
= 0;
355 public static final int PARAMETER_TYPE_COLUMN
= 1;
356 public static final int PARAMETER_NAME_COLUMN
= 2;
358 public int getRowCount() {
359 return getVariableData().length
;
362 public int getColumnCount() {
366 public Object
getValueAt(int rowIndex
, int columnIndex
) {
367 switch (columnIndex
) {
368 case CHECKMARK_COLUMN
: {
369 return getVariableData()[rowIndex
].passAsParameter ? Boolean
.TRUE
: Boolean
.FALSE
;
371 case PARAMETER_NAME_COLUMN
: {
372 return getVariableData()[rowIndex
].name
;
374 case PARAMETER_TYPE_COLUMN
: {
375 return getVariableData()[rowIndex
].type
.getPresentableText();
382 public void setValueAt(Object aValue
, int rowIndex
, int columnIndex
) {
383 switch (columnIndex
) {
384 case CHECKMARK_COLUMN
: {
385 getVariableData()[rowIndex
].passAsParameter
= ((Boolean
)aValue
).booleanValue();
386 fireTableRowsUpdated(rowIndex
, rowIndex
);
387 myTable
.getSelectionModel().setSelectionInterval(rowIndex
, rowIndex
);
391 case PARAMETER_NAME_COLUMN
: {
392 VariableData data
= getVariableData()[rowIndex
];
393 String name
= (String
)aValue
;
394 if (JavaPsiFacade
.getInstance(myProject
).getNameHelper().isIdentifier(name
)) {
400 case PARAMETER_TYPE_COLUMN
: {
401 VariableData data
= getVariableData()[rowIndex
];
402 data
.type
= (PsiType
)aValue
;
409 public boolean isCellEditable(int rowIndex
, int columnIndex
) {
410 switch (columnIndex
) {
411 case CHECKMARK_COLUMN
:
413 case PARAMETER_NAME_COLUMN
:
414 return isEnabled() && getVariableData()[rowIndex
].passAsParameter
;
415 case PARAMETER_TYPE_COLUMN
:
416 return isEnabled() && getVariableData()[rowIndex
].passAsParameter
&& !(myParameterTypeSelectors
[rowIndex
].getComponent() instanceof JLabel
);
422 public Class
getColumnClass(int columnIndex
) {
423 if (columnIndex
== CHECKMARK_COLUMN
) {
424 return Boolean
.class;
426 return super.getColumnClass(columnIndex
);
430 private class CheckBoxTableCellRenderer
extends BooleanTableCellRenderer
{
431 public Component
getTableCellRendererComponent(JTable table
, Object value
, boolean isSelected
, boolean hasFocus
, int row
, int column
) {
432 Component rendererComponent
= super.getTableCellRendererComponent(table
, value
, isSelected
, hasFocus
, row
, column
);
433 rendererComponent
.setEnabled(ParameterTablePanel
.this.isEnabled());
434 return rendererComponent
;