provided navigation in DomCollection Control
[fedora-idea.git] / openapi / src / com / intellij / util / xml / ui / DomCollectionControl.java
blobcda4f9765b4bb926888e87a7a44ffa3b0187abeb
1 /*
2 * Copyright (c) 2005 Your Corporation. All Rights Reserved.
3 */
4 package com.intellij.util.xml.ui;
6 import com.intellij.j2ee.j2eeDom.xmlData.ReadOnlyDeploymentDescriptorModificationException;
7 import com.intellij.javaee.ui.Warning;
8 import com.intellij.openapi.actionSystem.AnAction;
9 import com.intellij.openapi.actionSystem.AnActionEvent;
10 import com.intellij.openapi.application.ApplicationManager;
11 import com.intellij.openapi.application.Result;
12 import com.intellij.openapi.command.WriteCommandAction;
13 import com.intellij.openapi.project.Project;
14 import com.intellij.openapi.util.Comparing;
15 import com.intellij.util.Consumer;
16 import com.intellij.util.EventDispatcher;
17 import com.intellij.util.ui.ColumnInfo;
18 import com.intellij.util.xml.DomElement;
19 import com.intellij.util.xml.DomUtil;
20 import com.intellij.util.xml.reflect.DomCollectionChildDescription;
21 import com.intellij.util.xml.ui.actions.DefaultAddAction;
22 import org.jetbrains.annotations.NonNls;
23 import org.jetbrains.annotations.Nullable;
25 import javax.swing.*;
26 import javax.swing.table.*;
27 import java.awt.*;
28 import java.util.ArrayList;
29 import java.util.Collections;
30 import java.util.List;
32 /**
33 * @author peter
35 public class DomCollectionControl<T extends DomElement> implements DomUIControl {
36 private final EventDispatcher<CommitListener> myDispatcher = EventDispatcher.create(CommitListener.class);
37 protected DomCollectionPanel myCollectionPanel;
39 private final List<T> myData = new ArrayList<T>();
40 private final DomElement myParentDomElement;
41 private final DomCollectionChildDescription myChildDescription;
42 private ColumnInfo<T, ?>[] myColumnInfos;
43 private boolean myEditable = false;
45 public DomCollectionControl(DomElement parentElement,
46 DomCollectionChildDescription description,
47 final boolean editable,
48 ColumnInfo<T, ?>... columnInfos) {
49 myChildDescription = description;
50 myParentDomElement = parentElement;
51 myColumnInfos = columnInfos;
52 myEditable = editable;
55 public DomCollectionControl(DomElement parentElement,
56 @NonNls String subTagName,
57 final boolean editable,
58 ColumnInfo<T, ?>... columnInfos) {
59 this(parentElement, parentElement.getGenericInfo().getCollectionChildDescription(subTagName), editable, columnInfos);
62 public DomCollectionControl(DomElement parentElement, DomCollectionChildDescription description) {
63 myChildDescription = description;
64 myParentDomElement = parentElement;
67 public DomCollectionControl(DomElement parentElement, @NonNls String subTagName) {
68 this(parentElement, parentElement.getGenericInfo().getCollectionChildDescription(subTagName));
71 public boolean isEditable() {
72 return myEditable;
75 public final ColumnInfo<T, ?>[] getColumnInfos() {
76 return myColumnInfos;
79 public void bind(JComponent component) {
80 assert component instanceof DomCollectionPanel;
82 initialize((DomCollectionPanel)component);
85 public void addCommitListener(CommitListener listener) {
86 myDispatcher.addListener(listener);
89 public void removeCommitListener(CommitListener listener) {
90 myDispatcher.removeListener(listener);
94 public boolean canNavigate(DomElement element) {
95 final Class<DomElement> aClass = (Class<DomElement>)DomUtil.getRawType(myChildDescription.getType());
97 final DomElement domElement = element.getParentOfType(aClass, false);
99 return domElement != null && myData.contains(domElement);
102 public void navigate(DomElement element) {
103 final Class<DomElement> aClass = (Class<DomElement>)DomUtil.getRawType(myChildDescription.getType());
104 final DomElement domElement = element.getParentOfType(aClass, false);
106 int index = myData.indexOf(domElement);
107 if (index < 0) index = 0;
109 myCollectionPanel.getTable().setRowSelectionInterval(index, index);
112 protected void initialize(final DomCollectionPanel boundComponent) {
113 if (boundComponent == null) {
114 myCollectionPanel = new DomCollectionPanel();
116 else {
117 myCollectionPanel = boundComponent;
119 myCollectionPanel.setControl(this);
120 myColumnInfos = createColumnInfos(myParentDomElement);
122 reset();
123 initializeTable();
126 protected ColumnInfo[] createColumnInfos(DomElement parent) {
127 return myColumnInfos;
130 protected void initializeTable() {
131 JTable table = myCollectionPanel.getTable();
133 myCollectionPanel.setTableModel(new AbstractTableModel() {
134 public int getRowCount() {
135 return myData.size();
138 public int getColumnCount() {
139 return myColumnInfos.length;
142 public boolean isCellEditable(int rowIndex, int columnIndex) {
143 return myColumnInfos[columnIndex].isCellEditable(myData.get(rowIndex));
146 public String getColumnName(int column) {
147 return myColumnInfos[column].getName();
150 public Class getColumnClass(int columnIndex) {
151 return myColumnInfos[columnIndex].getColumnClass();
154 public void setValueAt(final Object aValue, final int rowIndex, final int columnIndex) {
155 final Object oldValue = getValueAt(rowIndex, columnIndex);
156 if (!Comparing.equal(oldValue, aValue)) {
157 performWriteCommandAction(new WriteCommandAction(getProject()) {
158 protected void run(final Result result) throws Throwable {
159 ((ColumnInfo<T, Object>)myColumnInfos[columnIndex]).setValue(myData.get(rowIndex), aValue);
165 public Object getValueAt(int rowIndex, int columnIndex) {
166 return myColumnInfos[columnIndex].valueOf(myData.get(rowIndex));
170 adjustColumnWidths(table);
171 fireTableChanged();
174 private void adjustColumnWidths(final JTable table) {
175 for (int i = 0; i < myColumnInfos.length; i++) {
176 ColumnInfo<T, ?> columnInfo = myColumnInfos[i];
177 final TableColumn column = table.getColumnModel().getColumn(i);
178 final TableCellRenderer cellRenderer = columnInfo.getRenderer(null);
179 if (cellRenderer != null) {
180 column.setCellRenderer(cellRenderer);
182 int width = -1;
183 for (int j = 0; j < myData.size(); j++) {
184 T t = myData.get(j);
185 final Component component = cellRenderer.getTableCellRendererComponent(table, columnInfo.valueOf(t), false, false, j, i);
186 final int prefWidth = component.getPreferredSize().width;
187 if (prefWidth > width) {
188 width = prefWidth;
191 if (width > 0) {
192 column.setPreferredWidth(width);
195 final TableCellEditor cellEditor = columnInfo.getEditor(null);
196 if (cellEditor != null) {
197 column.setCellEditor(cellEditor);
202 public final void columnsChanged() {
203 myColumnInfos = createColumnInfos(myParentDomElement);
204 final JTable table = myCollectionPanel.getTable();
205 ((AbstractTableModel)table.getModel()).fireTableStructureChanged();
206 adjustColumnWidths(table);
209 protected void doEdit() {
210 doEdit(myData.get(myCollectionPanel.getTable().getSelectedRow()));
213 protected void doEdit(final T t) {
214 final DomEditorManager manager = getDomEditorManager(this);
215 if (manager != null) {
216 manager.openDomElementEditor(t);
220 protected void removeInternal(final Consumer<T> consumer, final List<T> toDelete) {
221 new WriteCommandAction(getProject()) {
222 protected void run(Result result) throws Throwable {
223 for (final T t : toDelete) {
224 consumer.consume(t);
227 }.execute();
230 protected void doRemove() {
231 ApplicationManager.getApplication().invokeLater(new Runnable() {
232 public void run() {
233 final int[] selected = myCollectionPanel.getTable().getSelectedRows();
234 if (selected == null || selected.length == 0) return;
235 List<T> selectedElements = new ArrayList<T>(selected.length);
236 for (final int i : selected) {
237 selectedElements.add(myData.get(i));
239 removeInternal(new Consumer<T>() {
240 public void consume(final T t) {
241 if (t.isValid()) {
242 t.undefine();
244 myData.remove(t);
246 }, selectedElements);
248 myCollectionPanel.getTableModel().fireTableDataChanged();
249 int selection = selected[0];
250 if (selection >= myData.size()) {
251 selection = myData.size() - 1;
253 if (selection >= 0) {
254 myCollectionPanel.getTable().setRowSelectionInterval(selection, selection);
260 protected static void performWriteCommandAction(final WriteCommandAction writeCommandAction) {
261 writeCommandAction.execute();
264 public void commit() throws ReadOnlyDeploymentDescriptorModificationException {
265 final CommitListener listener = myDispatcher.getMulticaster();
266 listener.beforeCommit(this);
267 listener.afterCommit(this);
270 public void dispose() {
271 if (myCollectionPanel != null) {
272 myCollectionPanel.dispose();
276 protected final Project getProject() {
277 return myParentDomElement.getManager().getProject();
280 public JComponent getFocusedComponent() {
281 return getBoundComponent();
284 public JComponent getBoundComponent() {
285 return getComponent();
288 public JComponent getComponent() {
289 if (myCollectionPanel == null) initialize(null);
291 return myCollectionPanel;
294 public final DomCollectionChildDescription getChildDescription() {
295 return myChildDescription;
298 public final List<? extends T> getCollectionElements() {
299 return (List<? extends T>)myChildDescription.getValues(myParentDomElement);
302 public final DomElement getDomElement() {
303 return myParentDomElement;
306 public List<Warning> getWarnings() {
307 return Collections.emptyList();
310 public final void reset() {
311 myData.clear();
312 myData.addAll(getData());
313 if (myCollectionPanel != null) {
314 fireTableChanged();
318 private void fireTableChanged() {
319 final int row = myCollectionPanel.getTable().getSelectedRow();
320 myCollectionPanel.getTableModel().fireTableDataChanged();
321 if (row >= 0 && row < myData.size()) {
322 myCollectionPanel.getTable().getSelectionModel().setSelectionInterval(row, row);
326 public List<T> getData() {
327 return (List<T>)myChildDescription.getValues(myParentDomElement);
330 @Nullable
331 protected AnAction[] createAdditionActions() {
332 return null;
335 protected DefaultAddAction createDefaultAction(final String name, final Icon icon, final Class s) {
336 return new ControlAddAction(name, "", icon) {
337 protected Class getElementClass() {
338 return s;
343 protected final Class<? extends T> getCollectionElementClass() {
344 return (Class<? extends T>)DomUtil.getRawType(myChildDescription.getType());
348 @Nullable
349 private static DomEditorManager getDomEditorManager(DomUIControl control) {
350 JComponent component = control.getComponent();
351 while (component != null && !(component instanceof DomEditorManager)) {
352 final Container parent = component.getParent();
353 if (!(parent instanceof JComponent)) {
354 return null;
356 component = (JComponent)parent;
358 return (DomEditorManager)component;
361 public class ControlAddAction extends DefaultAddAction<T> {
363 public ControlAddAction() {
366 public ControlAddAction(final String text) {
367 super(text);
370 public ControlAddAction(final String text, final String description, final Icon icon) {
371 super(text, description, icon);
374 protected final DomCollectionChildDescription getDomCollectionChildDescription() {
375 return myChildDescription;
378 protected final DomElement getParentDomElement() {
379 return myParentDomElement;
382 protected void afterAddition(final JTable table, final int rowIndex) {
383 table.setRowSelectionInterval(rowIndex, rowIndex);
386 protected final void afterAddition(final AnActionEvent e, final DomElement newElement) {
387 if (newElement != null) {
388 reset();
389 afterAddition(myCollectionPanel.getTable(), myData.size() - 1);