1 package com
.intellij
.refactoring
.ui
;
3 import com
.intellij
.openapi
.actionSystem
.DataKey
;
4 import com
.intellij
.openapi
.actionSystem
.DataSink
;
5 import com
.intellij
.openapi
.actionSystem
.LangDataKeys
;
6 import com
.intellij
.openapi
.actionSystem
.TypeSafeDataProvider
;
7 import com
.intellij
.openapi
.util
.IconLoader
;
8 import com
.intellij
.psi
.PsiElement
;
9 import com
.intellij
.refactoring
.RefactoringBundle
;
10 import com
.intellij
.refactoring
.classMembers
.MemberInfoBase
;
11 import com
.intellij
.refactoring
.classMembers
.MemberInfoChange
;
12 import com
.intellij
.refactoring
.classMembers
.MemberInfoChangeListener
;
13 import com
.intellij
.refactoring
.classMembers
.MemberInfoModel
;
14 import com
.intellij
.ui
.BooleanTableCellRenderer
;
15 import com
.intellij
.ui
.ColoredTableCellRenderer
;
16 import com
.intellij
.ui
.RowIcon
;
17 import com
.intellij
.ui
.SimpleTextAttributes
;
18 import com
.intellij
.util
.ui
.EmptyIcon
;
19 import com
.intellij
.util
.ui
.Table
;
20 import org
.jetbrains
.annotations
.NotNull
;
23 import javax
.swing
.table
.AbstractTableModel
;
24 import javax
.swing
.table
.TableColumnModel
;
26 import java
.util
.ArrayList
;
27 import java
.util
.Collection
;
28 import java
.util
.Collections
;
29 import java
.util
.List
;
32 * @author Dennis.Ushakov
34 public abstract class AbstractMemberSelectionTable
<T
extends PsiElement
, M
extends MemberInfoBase
<T
>> extends Table
implements TypeSafeDataProvider
{
35 protected static final int CHECKED_COLUMN
= 0;
36 protected static final int DISPLAY_NAME_COLUMN
= 1;
37 protected static final int ABSTRACT_COLUMN
= 2;
38 protected static final Icon OVERRIDING_METHOD_ICON
= IconLoader
.getIcon("/general/overridingMethod.png");
39 protected static final Icon IMPLEMENTING_METHOD_ICON
= IconLoader
.getIcon("/general/implementingMethod.png");
40 protected static final Icon EMPTY_OVERRIDE_ICON
= new EmptyIcon(16, 16);
41 protected final String myAbstractColumnHeader
;
42 protected static final String DISPLAY_NAME_COLUMN_HEADER
= RefactoringBundle
.message("member.column");
43 protected List
<M
> myMemberInfos
;
44 protected final boolean myAbstractEnabled
;
45 protected MemberInfoModel
<T
, M
> myMemberInfoModel
;
46 protected MyTableModel
<T
, M
> myTableModel
;
47 protected static final int OVERRIDE_ICON_POSITION
= 2;
48 protected static final int VISIBILITY_ICON_POSITION
= 1;
49 protected static final int MEMBER_ICON_POSITION
= 0;
51 public AbstractMemberSelectionTable(Collection
<M
> memberInfos
, MemberInfoModel
<T
, M
> memberInfoModel
, String abstractColumnHeader
) {
52 myAbstractEnabled
= abstractColumnHeader
!= null;
53 myAbstractColumnHeader
= abstractColumnHeader
;
54 myTableModel
= new MyTableModel
<T
, M
>(this);
56 myMemberInfos
= new ArrayList
<M
>(memberInfos
);
57 if (memberInfoModel
!= null) {
58 myMemberInfoModel
= memberInfoModel
;
61 myMemberInfoModel
= new DefaultMemberInfoModel
<T
, M
>();
64 setModel(myTableModel
);
66 TableColumnModel model
= getColumnModel();
67 model
.getColumn(DISPLAY_NAME_COLUMN
).setCellRenderer(new MyTableRenderer
<T
, M
>(this));
68 model
.getColumn(CHECKED_COLUMN
).setCellRenderer(new MyBooleanRenderer
<T
, M
>(this));
69 final int checkBoxWidth
= new JCheckBox().getPreferredSize().width
;
70 model
.getColumn(CHECKED_COLUMN
).setMaxWidth(checkBoxWidth
);
71 model
.getColumn(CHECKED_COLUMN
).setMinWidth(checkBoxWidth
);
73 if (myAbstractEnabled
) {
75 (int)(1.3 * getFontMetrics(getFont()).charsWidth(myAbstractColumnHeader
.toCharArray(), 0,
76 myAbstractColumnHeader
.length()));
77 model
.getColumn(ABSTRACT_COLUMN
).setMaxWidth(width
);
78 model
.getColumn(ABSTRACT_COLUMN
).setPreferredWidth(width
);
79 model
.getColumn(ABSTRACT_COLUMN
).setCellRenderer(new MyBooleanRenderer
<T
, M
>(this));
82 setPreferredScrollableViewportSize(new Dimension(400, getRowHeight() * 12));
83 getSelectionModel().setSelectionMode(ListSelectionModel
.MULTIPLE_INTERVAL_SELECTION
);
85 setIntercellSpacing(new Dimension(0, 0));
87 new MyEnableDisableAction().register();
90 public Collection
<M
> getSelectedMemberInfos() {
91 ArrayList
<M
> list
= new ArrayList
<M
>(myMemberInfos
.size());
92 for (M info
: myMemberInfos
) {
93 if (isMemberInfoSelected(info
)) {
94 // if (info.isChecked() || (!myMemberInfoModel.isMemberEnabled(info) && myMemberInfoModel.isCheckedWhenDisabled(info))) {
101 private boolean isMemberInfoSelected(final M info
) {
102 final boolean memberEnabled
= myMemberInfoModel
.isMemberEnabled(info
);
103 return (memberEnabled
&& info
.isChecked()) || (!memberEnabled
&& myMemberInfoModel
.isCheckedWhenDisabled(info
));
106 public MemberInfoModel
<T
, M
> getMemberInfoModel() {
107 return myMemberInfoModel
;
110 public void setMemberInfoModel(MemberInfoModel
<T
, M
> memberInfoModel
) {
111 myMemberInfoModel
= memberInfoModel
;
114 public void fireExternalDataChange() {
115 myTableModel
.fireTableDataChanged();
118 public void setMemberInfos(Collection
<M
> memberInfos
) {
119 myMemberInfos
= new ArrayList
<M
>(memberInfos
);
120 fireMemberInfoChange(memberInfos
);
121 myTableModel
.fireTableDataChanged();
124 public void addMemberInfoChangeListener(MemberInfoChangeListener
<T
, M
> l
) {
125 listenerList
.add(MemberInfoChangeListener
.class, l
);
128 protected void fireMemberInfoChange(Collection
<M
> changedMembers
) {
129 Object
[] list
= listenerList
.getListenerList();
131 MemberInfoChange event
= new MemberInfoChange
<T
, M
>(changedMembers
);
132 for (Object element
: list
) {
133 if (element
instanceof MemberInfoChangeListener
) {
134 ((MemberInfoChangeListener
<T
, M
>)element
).memberInfoChanged(event
);
139 public void calcData(final DataKey key
, final DataSink sink
) {
140 if (key
== LangDataKeys
.PSI_ELEMENT
) {
141 final Collection
<M
> memberInfos
= getSelectedMemberInfos();
142 if (memberInfos
.size() > 0) {
143 sink
.put(LangDataKeys
.PSI_ELEMENT
, memberInfos
.iterator().next().getMember());
148 public void scrollSelectionInView() {
149 for(int i
=0; i
<myMemberInfos
.size(); i
++) {
150 if (isMemberInfoSelected(myMemberInfos
.get(i
))) {
151 Rectangle rc
= getCellRect(i
, 0, false);
152 scrollRectToVisible(rc
);
158 public void addNotify() {
160 scrollSelectionInView();
163 protected abstract Object
getAbstractColumnValue(M memberInfo
);
165 protected abstract boolean isAbstractColumnEditable(int rowIndex
);
167 protected abstract void setVisibilityIcon(M memberInfo
, RowIcon icon
);
169 protected abstract Icon
getOverrideIcon(M memberInfo
);
171 private static class DefaultMemberInfoModel
<T
extends PsiElement
, M
extends MemberInfoBase
<T
>> implements MemberInfoModel
<T
, M
> {
172 public boolean isMemberEnabled(M member
) {
176 public boolean isCheckedWhenDisabled(M member
) {
180 public boolean isAbstractEnabled(M member
) {
184 public boolean isAbstractWhenDisabled(M member
) {
189 public int checkForProblems(@NotNull M member
) {
193 public void memberInfoChanged(MemberInfoChange
<T
, M
> event
) {
196 public Boolean
isFixedAbstract(M member
) {
200 public String
getTooltipText(M member
) {
205 private static class MyTableModel
<T
extends PsiElement
, M
extends MemberInfoBase
<T
>> extends AbstractTableModel
{
206 private final AbstractMemberSelectionTable
<T
, M
> myTable
;
208 public MyTableModel(AbstractMemberSelectionTable
<T
, M
> table
) {
212 public int getColumnCount() {
213 if (myTable
.myAbstractEnabled
) {
221 public int getRowCount() {
222 return myTable
.myMemberInfos
.size();
225 public Class
getColumnClass(int columnIndex
) {
226 if (columnIndex
== CHECKED_COLUMN
|| columnIndex
== ABSTRACT_COLUMN
) {
227 return Boolean
.class;
229 return super.getColumnClass(columnIndex
);
232 public Object
getValueAt(int rowIndex
, int columnIndex
) {
233 final M memberInfo
= myTable
.myMemberInfos
.get(rowIndex
);
234 switch (columnIndex
) {
236 if (myTable
.myMemberInfoModel
.isMemberEnabled(memberInfo
)) {
237 return memberInfo
.isChecked() ? Boolean
.TRUE
: Boolean
.FALSE
;
240 return myTable
.myMemberInfoModel
.isCheckedWhenDisabled(memberInfo
);
242 case ABSTRACT_COLUMN
:
244 return myTable
.getAbstractColumnValue(memberInfo
);
246 case DISPLAY_NAME_COLUMN
:
247 return memberInfo
.getDisplayName();
249 throw new RuntimeException("Incorrect column index");
253 public String
getColumnName(int column
) {
257 case ABSTRACT_COLUMN
:
258 return myTable
.myAbstractColumnHeader
;
259 case DISPLAY_NAME_COLUMN
:
260 return DISPLAY_NAME_COLUMN_HEADER
;
262 throw new RuntimeException("Incorrect column index");
266 public boolean isCellEditable(int rowIndex
, int columnIndex
) {
267 switch (columnIndex
) {
269 return myTable
.myMemberInfoModel
.isMemberEnabled(myTable
.myMemberInfos
.get(rowIndex
));
270 case ABSTRACT_COLUMN
:
271 return myTable
.isAbstractColumnEditable(rowIndex
);
277 public void setValueAt(final Object aValue
, final int rowIndex
, final int columnIndex
) {
278 if (columnIndex
== CHECKED_COLUMN
) {
279 myTable
.myMemberInfos
.get(rowIndex
).setChecked(((Boolean
)aValue
).booleanValue());
281 else if (columnIndex
== ABSTRACT_COLUMN
) {
282 myTable
.myMemberInfos
.get(rowIndex
).setToAbstract(((Boolean
)aValue
).booleanValue());
285 Collection
<M
> changed
= Collections
.singletonList(myTable
.myMemberInfos
.get(rowIndex
));
286 myTable
.fireMemberInfoChange(changed
);
287 fireTableDataChanged();
288 // fireTableRowsUpdated(rowIndex, rowIndex);
292 private class MyEnableDisableAction
extends EnableDisableAction
{
294 protected JTable
getTable() {
295 return AbstractMemberSelectionTable
.this;
298 protected void applyValue(int[] rows
, boolean valueToBeSet
) {
299 List
<M
> changedInfo
= new ArrayList
<M
>();
300 for (int row
: rows
) {
301 final M memberInfo
= myMemberInfos
.get(row
);
302 memberInfo
.setChecked(valueToBeSet
);
303 changedInfo
.add(memberInfo
);
305 fireMemberInfoChange(changedInfo
);
306 final int selectedRow
= getSelectedRow();
307 myTableModel
.fireTableDataChanged();
308 setRowSelectionInterval(selectedRow
, selectedRow
);
311 protected boolean isRowChecked(final int row
) {
312 return myMemberInfos
.get(row
).isChecked();
316 private static class MyTableRenderer
<T
extends PsiElement
, M
extends MemberInfoBase
<T
>> extends ColoredTableCellRenderer
{
317 private final AbstractMemberSelectionTable
<T
, M
> myTable
;
319 public MyTableRenderer(AbstractMemberSelectionTable
<T
, M
> table
) {
323 public void customizeCellRenderer(JTable table
, final Object value
,
324 boolean isSelected
, boolean hasFocus
, final int row
, final int column
) {
326 final int modelColumn
= myTable
.convertColumnIndexToModel(column
);
327 final M memberInfo
= myTable
.myMemberInfos
.get(row
);
328 setToolTipText(myTable
.myMemberInfoModel
.getTooltipText(memberInfo
));
329 T member
= memberInfo
.getMember();
330 switch (modelColumn
) {
331 case DISPLAY_NAME_COLUMN
:
333 Icon memberIcon
= myTable
.getMemberIcon(memberInfo
, 0);
334 Icon overrideIcon
= myTable
.getOverrideIcon(memberInfo
);
336 RowIcon icon
= new RowIcon(3);
337 icon
.setIcon(memberIcon
, MEMBER_ICON_POSITION
);
338 myTable
.setVisibilityIcon(memberInfo
, icon
);
339 icon
.setIcon(overrideIcon
, OVERRIDE_ICON_POSITION
);
348 final boolean cellEditable
= myTable
.myMemberInfoModel
.isMemberEnabled(memberInfo
);
349 setEnabled(cellEditable
);
351 if (value
== null) return;
352 final int problem
= myTable
.myMemberInfoModel
.checkForProblems(memberInfo
);
354 if (problem
== MemberInfoModel
.ERROR
) {
357 else if (problem
== MemberInfoModel
.WARNING
&& !isSelected
) {
360 append((String
)value
, new SimpleTextAttributes(Font
.PLAIN
, c
));
365 protected Icon
getMemberIcon(M memberInfo
, int flags
) {
366 return memberInfo
.getMember().getIcon(flags
);
369 private static class MyBooleanRenderer
<T
extends PsiElement
, M
extends MemberInfoBase
<T
>> extends BooleanTableCellRenderer
{
370 private final AbstractMemberSelectionTable
<T
, M
> myTable
;
372 public MyBooleanRenderer(AbstractMemberSelectionTable
<T
, M
> table
) {
376 public Component
getTableCellRendererComponent(JTable table
, Object value
,
377 boolean isSelected
, boolean hasFocus
,
378 int row
, int column
) {
379 Component component
= super.getTableCellRendererComponent(table
, value
, isSelected
, hasFocus
, row
, column
);
380 if (component
instanceof JComponent
) {
381 JComponent jComponent
= (JComponent
)component
;
382 int modelColumn
= myTable
.convertColumnIndexToModel(column
);
383 final M memberInfo
= myTable
.myMemberInfos
.get(row
);
385 jComponent
.setEnabled(
386 (modelColumn
== CHECKED_COLUMN
&& myTable
.myMemberInfoModel
.isMemberEnabled(memberInfo
)
387 || (modelColumn
== ABSTRACT_COLUMN
&& memberInfo
.isChecked() && myTable
.isAbstractColumnEditable(row
)))