common controls extracted to the platform + messages moved to the right bundle

This commit is contained in:
Kirill.Safonov
2010-04-05 14:53:43 +04:00
parent aaed92b37f
commit 4574d87dff
3 changed files with 489 additions and 0 deletions
@@ -0,0 +1,69 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.util.ui;
import com.intellij.openapi.fileChooser.FileChooser;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ui.AbstractTableCellEditor;
import com.intellij.util.ui.CellEditorComponentWithBrowseButton;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class LocalPathCellEditor extends AbstractTableCellEditor {
private final String myTitle;
private CellEditorComponentWithBrowseButton<JTextField> myComponent;
public LocalPathCellEditor(String title) {
myTitle = title;
}
public Object getCellEditorValue() {
return myComponent.getChildComponent().getText();
}
public Component getTableCellEditorComponent(final JTable table, Object value, boolean isSelected, final int row, int column) {
ActionListener listener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
FileChooserDescriptor d = new FileChooserDescriptor(false, true, false, true, false, false);
if (myTitle != null) {
d.setTitle(myTitle);
}
d.setShowFileSystemRoots(true);
VirtualFile initialFile = LocalFileSystem.getInstance().findFileByPath((String)getCellEditorValue());
VirtualFile[] files = FileChooser.chooseFiles(table, d, initialFile);
if (files.length == 1 && files[0] != null) {
String path = files[0].getPresentableUrl();
if (SystemInfo.isWindows && path.length() == 2 && Character.isLetter(path.charAt(0)) && path.charAt(1) == ':') {
path += "\\"; // make path absolute
}
myComponent.getChildComponent().setText(path);
}
}
};
myComponent = new CellEditorComponentWithBrowseButton<JTextField>(new TextFieldWithBrowseButton(listener), this);
myComponent.getChildComponent().setText((String)value);
return myComponent;
}
}
@@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.util.ui.ValidatingTableEditor">
<grid id="27dc6" binding="myContentPane" layout-manager="GridLayoutManager" row-count="4" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<xy x="20" y="20" width="500" height="400"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<scrollpane id="11f79">
<constraints>
<grid row="0" column="0" row-span="1" col-span="3" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<component id="37d9d" class="com.intellij.ui.table.TableView" binding="myTable" custom-create="true">
<constraints/>
<properties/>
</component>
</children>
</scrollpane>
<component id="38e47" class="javax.swing.JButton" binding="myAddButton" default-binding="true">
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="A&amp;dd"/>
</properties>
</component>
<component id="79576" class="javax.swing.JButton" binding="myRemoveButton" default-binding="true">
<constraints>
<grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="&amp;Remove"/>
</properties>
</component>
<hspacer id="ef5dc">
<constraints>
<grid row="1" column="2" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
</hspacer>
<grid id="a830f" layout-manager="GridLayoutManager" row-count="1" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="3" column="0" row-span="1" col-span="3" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<component id="b1d0" class="javax.swing.JLabel" binding="myMessageLabel">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Label"/>
</properties>
</component>
<hspacer id="a0645">
<constraints>
<grid row="0" column="2" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
</hspacer>
<component id="4d864" class="com.intellij.ui.HoverHyperlinkLabel" binding="myFixLink" custom-create="true">
<constraints>
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Fix"/>
</properties>
</component>
</children>
</grid>
<vspacer id="4ae4a">
<constraints>
<grid row="2" column="2" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
</constraints>
</vspacer>
</children>
</grid>
</form>
@@ -0,0 +1,337 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.util.ui;
import com.intellij.openapi.util.NullableComputable;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.ui.HoverHyperlinkLabel;
import com.intellij.ui.table.TableView;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public abstract class ValidatingTableEditor<Item> {
private static final Icon WARNING_ICON = UIUtil.getBalloonWarningIcon();
private static final Icon EMPTY_ICON = new EmptyIcon(WARNING_ICON);
private static final String REMOVE_KEY = "REMOVE_SELECTED";
public interface RowHeightProvider {
int getRowHeight();
}
public interface Fix extends Runnable {
String getTitle();
}
private class ColumnInfoWrapper extends ColumnInfo<Item, String> {
private final ColumnInfo<Item, String> myDelegate;
public ColumnInfoWrapper(ColumnInfo<Item, String> delegate) {
super(delegate.getName());
myDelegate = delegate;
}
@Override
public String valueOf(Item item) {
return myDelegate.valueOf(item);
}
@Override
public boolean isCellEditable(Item item) {
return myDelegate.isCellEditable(item);
}
@Override
public void setValue(Item item, String value) {
myDelegate.setValue(item, value);
updateMessage(-1, null);
}
@Override
public TableCellEditor getEditor(Item item) {
return myDelegate.getEditor(item);
}
}
private JPanel myContentPane;
private TableView<Item> myTable;
private JButton myAddButton;
private JButton myRemoveButton;
private JLabel myMessageLabel;
private HoverHyperlinkLabel myFixLink;
private final List<String> myWarnings = new ArrayList<String>();
private Fix myFixRunnable;
protected abstract Item cloneOf(Item item);
@Nullable
protected abstract Pair<String, Fix> validate(List<Item> current, List<String> warnings);
protected abstract Item createItem();
private class IconColumn extends ColumnInfo<Item, Object> implements RowHeightProvider {
public IconColumn() {
super(" ");
}
public String valueOf(Item item) {
return null;
}
@Override
public int getWidth(JTable table) {
return WARNING_ICON.getIconWidth() + 2;
}
public int getRowHeight() {
return WARNING_ICON.getIconHeight();
}
@Override
public TableCellRenderer getRenderer(final Item item) {
return new WarningIconCellRenderer(new NullableComputable<String>() {
public String compute() {
return myWarnings.get(doGetItems().indexOf(item));
}
});
}
}
private void createUIComponents() {
myTable = new ChangesTrackingTableView<Item>() {
protected void onTextChanged(int row, int column, String value) {
final Item original = getItems().get(row);
Item override = cloneOf(original);
final ColumnInfo<Item, String> columnInfo = getTableModel().getColumnInfos()[column];
columnInfo.setValue(override, value);
updateMessage(row, override);
}
@Override
protected void onEditingStopped() {
updateMessage(-1, null);
}
};
myFixLink = new HoverHyperlinkLabel(null);
}
protected ValidatingTableEditor() {
myTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
updateButtons();
}
});
myTable.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), REMOVE_KEY);
myTable.getActionMap().put(REMOVE_KEY, new AbstractAction() {
public void actionPerformed(final ActionEvent e) {
removeSelected();
}
});
myFixLink.addHyperlinkListener(new HyperlinkListener() {
public void hyperlinkUpdate(HyperlinkEvent e) {
if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED && myFixRunnable != null) {
myFixRunnable.run();
}
}
});
myAddButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
addItem();
}
});
myRemoveButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
removeSelected();
}
});
}
private void removeSelected() {
myTable.stopEditing();
List<Item> items = new ArrayList<Item>(doGetItems());
final int[] rows = myTable.getSelectedRows();
for (int i = rows.length - 1; i >= 0; i--) {
items.remove(rows[i]);
}
setItems(items);
updateMessage(-1, null);
if (!items.isEmpty()) {
int index = Math.min(rows[0], items.size() - 1);
myTable.getSelectionModel().addSelectionInterval(index, index);
}
}
protected void addItem() {
List<Item> items = new ArrayList<Item>(doGetItems());
items.add(createItem());
setItems(items);
final int row = items.size() - 1;
myTable.getSelectionModel().setSelectionInterval(row, row);
myTable.scrollRectToVisible(myTable.getCellRect(row, 0, true));
if (getTableModel().getColumnInfos()[1].isCellEditable(items.get(row))) {
myTable.editCellAt(row, 1);
IdeFocusManager.findInstanceByComponent(myContentPane).requestFocus(myTable.getEditorComponent(), true);
}
updateMessage(-1, null);
}
private ListTableModel<Item> getTableModel() {
return (ListTableModel<Item>)myTable.getModel();
}
public void setModel(ColumnInfo<Item, String>[] valueColumns, List<Item> items) {
ColumnInfo[] columns = new ColumnInfo[valueColumns.length + 1];
IconColumn iconColumn = new IconColumn();
int maxHeight = iconColumn.getRowHeight();
columns[0] = iconColumn;
for (int i = 0; i < valueColumns.length; i++) {
columns[i + 1] = new ColumnInfoWrapper(valueColumns[i]);
if (valueColumns[i] instanceof RowHeightProvider) {
maxHeight = Math.max(maxHeight, ((RowHeightProvider)valueColumns[i]).getRowHeight());
}
}
myTable.stopEditing();
myTable.setModel(new ListTableModel<Item>(columns));
if (maxHeight > 0) {
myTable.setRowHeight(maxHeight);
}
setItems(items);
updateMessage(-1, null);
}
public List<Item> getItems() {
return Collections.unmodifiableList(doGetItems());
}
private List<Item> doGetItems() {
List<Item> items = new ArrayList<Item>(getTableModel().getItems());
if (myTable.isEditing()) {
Component c = myTable.getEditorComponent();
final JTextField textField;
if (c instanceof CellEditorComponentWithBrowseButton) {
textField = (JTextField)((CellEditorComponentWithBrowseButton)c).getChildComponent();
}
else {
textField = (JTextField)c;
}
String value = textField.getText();
ColumnInfo column = ((ListTableModel)myTable.getModel()).getColumnInfos()[myTable.getEditingColumn()];
((ColumnInfoWrapper)column).myDelegate.setValue(items.get(myTable.getEditingRow()), value);
}
return items;
}
private void setItems(List<Item> items) {
if (items.isEmpty()) {
getTableModel().setItems(Collections.<Item>emptyList());
myWarnings.clear();
}
else {
getTableModel().setItems(new ArrayList<Item>(items));
for (Item item : items) {
myWarnings.add(null);
}
}
updateButtons();
}
public void setTableHeader(JTableHeader header) {
myTable.setTableHeader(header);
}
private void updateButtons() {
myRemoveButton.setEnabled(myTable.getSelectedRow() != -1);
}
public void updateMessage(int index, @Nullable Item override) {
List<Item> current = new ArrayList<Item>(doGetItems());
if (override != null) {
current.set(index, override);
}
Pair<String, Fix> messageAndFix = validate(current, myWarnings);
if (messageAndFix != null) {
myMessageLabel.setText(messageAndFix.first);
myMessageLabel.setIcon(WARNING_ICON);
myMessageLabel.setVisible(true);
myFixRunnable = messageAndFix.second;
myFixLink.setVisible(myFixRunnable != null);
myFixLink.setText(myFixRunnable != null ? myFixRunnable.getTitle() : null);
}
else {
myMessageLabel.setText(" ");
myMessageLabel.setIcon(EMPTY_ICON);
myFixLink.setVisible(false);
myFixRunnable = null;
}
myTable.repaint();
}
public JComponent getPreferredFocusedComponent() {
return myTable;
}
private static class WarningIconCellRenderer extends DefaultTableCellRenderer {
private final NullableComputable<String> myWarningProvider;
public WarningIconCellRenderer(NullableComputable<String> warningProvider) {
myWarningProvider = warningProvider;
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
JLabel label = (JLabel)super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
String message = myWarningProvider.compute();
label.setIcon(message != null ? WARNING_ICON : null);
label.setToolTipText(message);
label.setHorizontalAlignment(CENTER);
label.setVerticalAlignment(CENTER);
return label;
}
}
}