| /* |
| * Copyright 2000-2009 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.lang.ant.config.impl.configuration; |
| |
| import com.intellij.openapi.util.Condition; |
| import com.intellij.openapi.util.Factory; |
| import com.intellij.openapi.util.JDOMExternalizable; |
| import com.intellij.ui.DocumentAdapter; |
| import com.intellij.ui.ListScrollingUtil; |
| import com.intellij.ui.SortedListModel; |
| import com.intellij.ui.TableUtil; |
| import com.intellij.ui.table.BaseTableView; |
| import com.intellij.util.config.AbstractProperty; |
| import com.intellij.util.config.ListProperty; |
| import com.intellij.util.config.StorageProperty; |
| import com.intellij.util.ui.ColumnInfo; |
| import com.intellij.util.ui.ListTableModel; |
| |
| import javax.swing.*; |
| import javax.swing.event.*; |
| import javax.swing.table.JTableHeader; |
| import javax.swing.table.TableCellEditor; |
| import javax.swing.table.TableColumn; |
| import javax.swing.table.TableColumnModel; |
| import javax.swing.text.JTextComponent; |
| import java.awt.event.ActionEvent; |
| import java.awt.event.ActionListener; |
| import java.awt.event.ItemEvent; |
| import java.awt.event.ItemListener; |
| import java.beans.PropertyChangeListener; |
| import java.beans.PropertyChangeSupport; |
| import java.util.*; |
| |
| public abstract class UIPropertyBinding { |
| public abstract void loadValues(AbstractProperty.AbstractPropertyContainer container); |
| |
| public abstract void apply(AbstractProperty.AbstractPropertyContainer container); |
| |
| public void beforeClose(AbstractProperty.AbstractPropertyContainer container) { |
| } |
| |
| public abstract void beDisabled(); |
| |
| public abstract void beEnabled(); |
| |
| public abstract void addAllPropertiesTo(Collection<AbstractProperty> properties); |
| |
| public static class Composite extends UIPropertyBinding { |
| private final ArrayList<UIPropertyBinding> myBindings = new ArrayList<UIPropertyBinding>(); |
| |
| public ToggleButtonBinding bindBoolean(JToggleButton toggleButton, AbstractProperty<Boolean> property) { |
| ToggleButtonBinding binding = new ToggleButtonBinding(toggleButton, property); |
| myBindings.add(binding); |
| return binding; |
| } |
| |
| public void bindInt(JTextComponent textComponent, AbstractProperty<Integer> property) { |
| myBindings.add(new IntTextBinding(textComponent, property)); |
| } |
| |
| public TextBinding bindString(JTextComponent textComponent, AbstractProperty<String> property) { |
| TextBinding textBinding = new TextBinding(textComponent, property); |
| myBindings.add(textBinding); |
| return textBinding; |
| } |
| |
| public void loadValues(AbstractProperty.AbstractPropertyContainer container) { |
| for (final UIPropertyBinding binding : myBindings) { |
| binding.loadValues(container); |
| } |
| } |
| |
| public void apply(AbstractProperty.AbstractPropertyContainer container) { |
| for (final UIPropertyBinding propertyBinding : myBindings) { |
| propertyBinding.apply(container); |
| } |
| } |
| |
| public void beforeClose(AbstractProperty.AbstractPropertyContainer container) { |
| for (final UIPropertyBinding binding : myBindings) { |
| binding.beforeClose(container); |
| } |
| } |
| |
| public void bindString(JComboBox comboBox, AbstractProperty<String> property) { |
| myBindings.add(new ComboBoxBinding(comboBox, property)); |
| } |
| |
| public <T extends JDOMExternalizable> TableListBinding<T> bindList(JTable table, ColumnInfo[] columns, ListProperty<T> property) { |
| final TableListBinding<T> binding = new TableListBinding<T>(table, columns, property); |
| myBindings.add(binding); |
| return binding; |
| } |
| |
| public void addBinding(UIPropertyBinding binding) { |
| myBindings.add(binding); |
| } |
| |
| public void beDisabled() { |
| for (final UIPropertyBinding binding : myBindings) { |
| binding.beDisabled(); |
| } |
| } |
| |
| public void beEnabled() { |
| for (final UIPropertyBinding binding : myBindings) { |
| binding.beEnabled(); |
| } |
| } |
| |
| public void addAllPropertiesTo(Collection<AbstractProperty> properties) { |
| for (final UIPropertyBinding binding : myBindings) { |
| binding.addAllPropertiesTo(properties); |
| } |
| } |
| |
| public <T> OrderListBinding<T> bindList(JList list, ListProperty<T> property) { |
| OrderListBinding<T> binding = new OrderListBinding<T>(list, property); |
| addBinding(binding); |
| return binding; |
| } |
| |
| public void bindString(JLabel label, AbstractProperty<String> property) { |
| addBinding(new ComponentBinding<JLabel, AbstractProperty<String>>(label, property) { |
| public void loadValues(AbstractProperty.AbstractPropertyContainer container) { |
| getComponent().setText(getProperty().get(container)); |
| } |
| |
| public void apply(AbstractProperty.AbstractPropertyContainer container) { |
| } |
| }); |
| } |
| } |
| |
| private static abstract class ComponentBinding<Comp extends JComponent, Prop extends AbstractProperty> extends UIPropertyBinding { |
| private final Comp myComponent; |
| private final Prop myProperty; |
| |
| protected ComponentBinding(Comp component, Prop property) { |
| myComponent = component; |
| myProperty = property; |
| } |
| |
| public void beDisabled() { |
| myComponent.setEnabled(false); |
| } |
| |
| public void beEnabled() { |
| myComponent.setEnabled(true); |
| } |
| |
| public void addAllPropertiesTo(Collection<AbstractProperty> properties) { |
| properties.add(myProperty); |
| } |
| |
| protected Comp getComponent() { |
| return myComponent; |
| } |
| |
| protected Prop getProperty() { |
| return myProperty; |
| } |
| } |
| |
| public static class ToggleButtonBinding extends ComponentBinding<JToggleButton, AbstractProperty<Boolean>> { |
| private final ChangeValueSupport myChangeSupport; |
| |
| public ToggleButtonBinding(JToggleButton toggleButton, AbstractProperty<Boolean> property) { |
| super(toggleButton, property); |
| myChangeSupport = ChangeValueSupport.create(toggleButton, ListenerInstaller.TOGGLE_BUTTON, property.getName()); |
| } |
| |
| public void loadValues(AbstractProperty.AbstractPropertyContainer container) { |
| myChangeSupport.stop(); |
| getComponent().setSelected(getProperty().get(container).booleanValue()); |
| myChangeSupport.start(); |
| } |
| |
| public void apply(AbstractProperty.AbstractPropertyContainer container) { |
| getProperty().set(container, getComponent().isSelected()); |
| } |
| |
| public void addChangeListener(PropertyChangeListener listener) { |
| myChangeSupport.addListener(listener); |
| } |
| |
| public void beforeClose(AbstractProperty.AbstractPropertyContainer container) { |
| myChangeSupport.stop(); |
| } |
| } |
| |
| private static abstract class ListenerInstaller<Comp extends JComponent, Listener> { |
| public static final ListenerInstaller<JToggleButton, ItemListener> TOGGLE_BUTTON = |
| new ListenerInstaller<JToggleButton, ItemListener>() { |
| public ItemListener create(final PropertyChangeSupport changeSupport, final String propertyName) { |
| return new ItemListener() { |
| public void itemStateChanged(ItemEvent e) { |
| changeSupport.firePropertyChange(propertyName, null, null); |
| } |
| }; |
| } |
| |
| public void setListener(JToggleButton component, ItemListener listener) { |
| component.getModel().addItemListener(listener); |
| } |
| |
| public void removeListener(JToggleButton component, ItemListener listener) { |
| component.getModel().removeItemListener(listener); |
| } |
| }; |
| |
| public abstract Listener create(PropertyChangeSupport changeSupport, String propertyName); |
| |
| public abstract void setListener(Comp component, Listener documentListener); |
| |
| public abstract void removeListener(Comp component, Listener changeListener); |
| |
| public final static ListenerInstaller<JTextComponent, DocumentListener> TEXT_LISTENER_INSTALLER = |
| new ListenerInstaller<JTextComponent, DocumentListener>() { |
| public DocumentListener create(final PropertyChangeSupport changeSupport, final String propertyName) { |
| return new DocumentAdapter() { |
| protected void textChanged(DocumentEvent e) { |
| changeSupport.firePropertyChange(propertyName, null, null); |
| } |
| }; |
| } |
| |
| public void setListener(JTextComponent textComponent, DocumentListener documentListener) { |
| textComponent.getDocument().addDocumentListener(documentListener); |
| } |
| |
| public void removeListener(JTextComponent textComponent, DocumentListener documentListener) { |
| textComponent.getDocument().removeDocumentListener(documentListener); |
| } |
| }; |
| } |
| |
| private static class ChangeValueSupport<Comp extends JComponent, Listener> { |
| private final Comp myComponent; |
| private final ListenerInstaller<Comp, Listener> myInstaller; |
| private final PropertyChangeSupport myChangeSupport; |
| private Listener myChangeListener = null; |
| private final String myPropertyName; |
| |
| public ChangeValueSupport(Comp component, ListenerInstaller<Comp, Listener> installer, String propertyName) { |
| myComponent = component; |
| myPropertyName = propertyName; |
| myChangeSupport = new PropertyChangeSupport(myPropertyName); |
| myInstaller = installer; |
| } |
| |
| public static <Comp extends JComponent, Listener> ChangeValueSupport create(Comp component, |
| ListenerInstaller<Comp, Listener> installer, |
| String propertyName) { |
| return new ChangeValueSupport(component, installer, propertyName); |
| } |
| |
| public void stop() { |
| if (myChangeListener != null) { |
| myInstaller.removeListener(myComponent, myChangeListener); |
| } |
| } |
| |
| public void start() { |
| if (myChangeListener != null) { |
| myInstaller.setListener(myComponent, myChangeListener); |
| } |
| |
| } |
| |
| public void addListener(PropertyChangeListener listener) { |
| myChangeSupport.addPropertyChangeListener(listener); |
| if (myChangeListener != null) { |
| return; |
| } |
| myChangeListener = myInstaller.create(myChangeSupport, myPropertyName); |
| myInstaller.setListener(myComponent, myChangeListener); |
| } |
| } |
| |
| public static class TextBinding extends ComponentBinding<JTextComponent, AbstractProperty<String>> { |
| private final ChangeValueSupport myChangeSupport; |
| |
| public TextBinding(JTextComponent textComponent, AbstractProperty<String> property) { |
| super(textComponent, property); |
| myChangeSupport = ChangeValueSupport.create(textComponent, ListenerInstaller.TEXT_LISTENER_INSTALLER, property.getName()); |
| } |
| |
| public void apply(AbstractProperty.AbstractPropertyContainer container) { |
| getProperty().set(container, getComponent().getText()); |
| } |
| |
| public void loadValues(AbstractProperty.AbstractPropertyContainer container) { |
| myChangeSupport.stop(); |
| loadValuesImpl(container); |
| myChangeSupport.start(); |
| } |
| |
| protected void loadValuesImpl(AbstractProperty.AbstractPropertyContainer container) { |
| getComponent().setText(getProperty().get(container)); |
| } |
| |
| public void addChangeListener(PropertyChangeListener listener) { |
| myChangeSupport.addListener(listener); |
| } |
| |
| public void beforeClose(AbstractProperty.AbstractPropertyContainer container) { |
| myChangeSupport.stop(); |
| } |
| } |
| |
| private static class IntTextBinding extends ComponentBinding<JTextComponent, AbstractProperty<Integer>> { |
| public IntTextBinding(JTextComponent textComponent, AbstractProperty<Integer> property) { |
| super(textComponent, property); |
| } |
| |
| public void loadValues(AbstractProperty.AbstractPropertyContainer container) { |
| getComponent().setText(getProperty().get(container).toString()); |
| } |
| |
| public void apply(AbstractProperty.AbstractPropertyContainer container) { |
| int value; |
| try { |
| value = Integer.parseInt(getComponent().getText()); |
| } |
| catch (NumberFormatException e) { |
| return; |
| } // TODO[dyoma] report error |
| getProperty().set(container, value); |
| } |
| } |
| |
| public static class TableListBinding<T> extends ComponentBinding<JTable, ListProperty<T>> { |
| private final ListProperty<T> myProperty; |
| private final ListTableModel<T> myModel; |
| private final Collection<JComponent> myComponents = new ArrayList<JComponent>(); |
| private StorageProperty myColumnWidthProperty; |
| |
| public TableListBinding(final JTable table, ColumnInfo[] columns, ListProperty<T> property) { |
| super(table, property); |
| myProperty = property; |
| myComponents.add(table); |
| final JTableHeader header = table.getTableHeader(); |
| header.setReorderingAllowed(false); |
| header.setResizingAllowed(false); |
| TableColumnModel columnModel = table.getColumnModel(); |
| myModel = new ListTableModel<T>(columns); |
| myModel.setSortable(false); |
| table.setModel(myModel); |
| for (int i = 0; i < columns.length; i++) { |
| ColumnInfo column = columns[i]; |
| TableColumn tableColumn = columnModel.getColumn(i); |
| TableCellEditor editor = column.getEditor(null); |
| if (editor != null) { |
| tableColumn.setCellEditor(editor); |
| } |
| int wight = column.getWidth(table); |
| if (wight > 0) { |
| tableColumn.setMinWidth(wight); |
| tableColumn.setMaxWidth(wight); |
| } |
| } |
| table.setSurrendersFocusOnKeystroke(true); |
| // support for sorting |
| myModel.addTableModelListener(new TableModelListener() { |
| public void tableChanged(final TableModelEvent e) { |
| final JTableHeader header = getComponent().getTableHeader(); |
| if (header != null) { |
| header.repaint(); |
| } |
| } |
| }); |
| } |
| |
| public void loadValues(AbstractProperty.AbstractPropertyContainer container) { |
| if (myColumnWidthProperty != null) { |
| BaseTableView.restoreWidth(myColumnWidthProperty.get(container), getComponent().getColumnModel()); |
| } |
| myModel.setItems(myProperty.getModifiableList(container)); |
| if (myModel.isSortable()) { |
| final ColumnInfo[] columnInfos = myModel.getColumnInfos(); |
| int sortByColumn = -1; |
| for (int idx = 0; idx < columnInfos.length; idx++) { |
| ColumnInfo columnInfo = columnInfos[idx]; |
| if (columnInfo.isSortable()) { |
| sortByColumn = idx; |
| break; |
| } |
| } |
| } |
| TableUtil.ensureSelectionExists(getComponent()); |
| } |
| |
| public void beDisabled() { |
| for (JComponent component : myComponents) { |
| component.setEnabled(false); |
| } |
| } |
| |
| public void beEnabled() { |
| for (JComponent component : myComponents) { |
| component.setEnabled(true); |
| } |
| } |
| |
| public void apply(AbstractProperty.AbstractPropertyContainer container) { |
| myProperty.set(container, myModel.getItems()); |
| } |
| |
| public void beforeClose(AbstractProperty.AbstractPropertyContainer container) { |
| if (myColumnWidthProperty != null) { |
| BaseTableView.storeWidth(myColumnWidthProperty.get(container), getComponent().getColumnModel()); |
| } |
| } |
| |
| public void setColumnWidths(StorageProperty property) { |
| myColumnWidthProperty = property; |
| getComponent().getTableHeader().setResizingAllowed(true); |
| } |
| |
| public void addAddFacility(JButton addButton, final Factory<T> factory) { |
| myComponents.add(addButton); |
| addButton.addActionListener(new ActionListener() { |
| public void actionPerformed(ActionEvent e) { |
| JTable table = getComponent(); |
| if (table.isEditing() && !table.getCellEditor().stopCellEditing()) { |
| return; |
| } |
| T item = factory.create(); |
| if (item == null) { |
| return; |
| } |
| ArrayList<T> items = new ArrayList<T>(myModel.getItems()); |
| items.add(item); |
| myModel.setItems(items); |
| int newIndex = myModel.indexOf(item); |
| ListSelectionModel selectionModel = table.getSelectionModel(); |
| selectionModel.clearSelection(); |
| selectionModel.setSelectionInterval(newIndex, newIndex); |
| ColumnInfo[] columns = myModel.getColumnInfos(); |
| for (int i = 0; i < columns.length; i++) { |
| ColumnInfo column = columns[i]; |
| if (column.isCellEditable(item)) { |
| table.requestFocusInWindow(); |
| table.editCellAt(newIndex, i); |
| break; |
| } |
| } |
| } |
| }); |
| } |
| |
| public void setSortable(boolean isSortable) { |
| myModel.setSortable(isSortable); |
| } |
| |
| public void addRemoveFacility(final JButton button, final Condition<T> removable) { |
| myComponents.add(button); |
| button.addActionListener(new ActionListener() { |
| public void actionPerformed(ActionEvent e) { |
| TableUtil.removeSelectedItems(getComponent()); |
| } |
| }); |
| getComponent().getSelectionModel().addListSelectionListener(new ListSelectionListener() { |
| public void valueChanged(ListSelectionEvent e) { |
| updateRemoveButton(button, removable); |
| } |
| }); |
| } |
| |
| public void updateRemoveButton(JButton button, Condition<T> removable) { |
| final JTable table = getComponent(); |
| final ListSelectionModel selectionModel = table.getSelectionModel(); |
| boolean enable = false; |
| if (!selectionModel.isSelectionEmpty()) { |
| enable = true; |
| for (int i : table.getSelectedRows()) { |
| if (!removable.value(myModel.getItems().get(i))) { |
| enable = false; |
| break; |
| } |
| } |
| } |
| button.setEnabled(enable); |
| } |
| } |
| |
| private static abstract class BaseListBinding<Item> extends UIPropertyBinding { |
| private final ArrayList<JComponent> myComponents = new ArrayList<JComponent>(); |
| private final JList myList; |
| private final ListProperty<Item> myProperty; |
| |
| protected BaseListBinding(ListProperty<Item> property, JList list) { |
| myList = list; |
| myProperty = property; |
| myComponents.add(myList); |
| } |
| |
| public void beDisabled() { |
| for (final JComponent component : myComponents) { |
| component.setEnabled(false); |
| } |
| } |
| |
| public void beEnabled() { |
| for (final JComponent component : myComponents) { |
| component.setEnabled(true); |
| } |
| } |
| |
| protected void addComponent(JComponent component) { |
| myComponents.add(component); |
| } |
| |
| public void apply(AbstractProperty.AbstractPropertyContainer container) { |
| ListModel model = myList.getModel(); |
| ArrayList<Item> list = new ArrayList<Item>(); |
| for (int i = 0; i < model.getSize(); i++) { |
| list.add((Item)model.getElementAt(i)); |
| } |
| myProperty.set(container, list); |
| } |
| |
| public void addAllPropertiesTo(Collection<AbstractProperty> properties) { |
| properties.add(myProperty); |
| } |
| |
| protected JList getList() { |
| return myList; |
| } |
| |
| protected ListProperty<Item> getProperty() { |
| return myProperty; |
| } |
| } |
| |
| public static class SortedListBinding<T extends JDOMExternalizable> extends BaseListBinding<T> { |
| public SortedListBinding(JList list, ListProperty<T> property, Comparator<T> comparator) { |
| super(property, list); |
| list.setModel(new SortedListModel<T>(comparator)); |
| } |
| |
| public void loadValues(AbstractProperty.AbstractPropertyContainer container) { |
| getModel().setAll(getProperty().get(container)); |
| ListScrollingUtil.ensureSelectionExists(getList()); |
| } |
| |
| private SortedListModel<T> getModel() { |
| return ((SortedListModel<T>)getList().getModel()); |
| } |
| } |
| |
| public static class OrderListBinding<T> extends BaseListBinding<T> { |
| public OrderListBinding(JList list, ListProperty<T> property) { |
| super(property, list); |
| list.setModel(new DefaultListModel()); |
| } |
| |
| public void loadValues(AbstractProperty.AbstractPropertyContainer container) { |
| DefaultListModel model = getModel(); |
| model.clear(); |
| Iterator iterator = getProperty().getIterator(container); |
| while (iterator.hasNext()) { |
| Object item = iterator.next(); |
| model.addElement(item); |
| } |
| ListScrollingUtil.ensureSelectionExists(getList()); |
| } |
| |
| private DefaultListModel getModel() { |
| return ((DefaultListModel)getList().getModel()); |
| } |
| |
| public void addAddManyFacility(JButton button, final Factory<List<T>> factory) { |
| button.addActionListener(new ActionListener() { |
| public void actionPerformed(ActionEvent e) { |
| List<T> items = factory.create(); |
| getList().requestFocusInWindow(); |
| if (items == null || items.size() == 0) { |
| return; |
| } |
| for (final T item : items) { |
| getModel().addElement(item); |
| ListScrollingUtil.selectItem(getList(), item); |
| } |
| } |
| }); |
| addComponent(button); |
| } |
| } |
| |
| public static class ComboBoxBinding extends ComponentBinding<JComboBox, AbstractProperty<String>> { |
| public ComboBoxBinding(JComboBox comboBox, AbstractProperty<String> property) { |
| super(comboBox, property); |
| } |
| |
| public void loadValues(AbstractProperty.AbstractPropertyContainer container) { |
| getComponent().getModel().setSelectedItem(getProperty().get(container)); |
| } |
| |
| public void apply(AbstractProperty.AbstractPropertyContainer container) { |
| getProperty().set(container, (String)getComponent().getSelectedItem()); |
| } |
| } |
| } |