From 7ddf6a845d814261a5356396ce808094dc5e259f Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Wed, 8 Jan 2014 13:00:38 +0100 Subject: [PATCH] continue WEB-2093: fix editing --- .../src/messages/XmlBundle.properties | 2 - .../ide/browsers/BrowserSettingsPanel.java | 170 ++++++++--------- .../ide/browsers/ConfigurableWebBrowser.java | 4 +- .../ide/browsers/TableModelEditor.java | 174 +++++++++++------- 4 files changed, 187 insertions(+), 163 deletions(-) diff --git a/platform/platform-resources-en/src/messages/XmlBundle.properties b/platform/platform-resources-en/src/messages/XmlBundle.properties index c8050b83f8de..6bce1e458047 100644 --- a/platform/platform-resources-en/src/messages/XmlBundle.properties +++ b/platform/platform-resources-en/src/messages/XmlBundle.properties @@ -154,8 +154,6 @@ browsers.opera=Opera browsers.firefox=Firefox browsers.chrome=Chrome browser.description=Open file in {0} -browser.active=Active -browser.default.settings=Default browser.error=Browser Error web.editor.configuration.title=Web browser.select.in.default.name=Web Browser diff --git a/xml/impl/src/com/intellij/ide/browsers/BrowserSettingsPanel.java b/xml/impl/src/com/intellij/ide/browsers/BrowserSettingsPanel.java index 7860a80bd712..e10198980513 100644 --- a/xml/impl/src/com/intellij/ide/browsers/BrowserSettingsPanel.java +++ b/xml/impl/src/com/intellij/ide/browsers/BrowserSettingsPanel.java @@ -24,7 +24,6 @@ import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.SystemInfo; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.IdeBorderFactory; import com.intellij.util.Function; @@ -45,6 +44,85 @@ import static com.intellij.ide.browsers.BrowsersConfiguration.BrowserFamily; import static com.intellij.ide.browsers.TableModelEditor.EditableColumnInfo; public class BrowserSettingsPanel { + private static final FileChooserDescriptor APP_FILE_CHOOSER_DESCRIPTOR = + SystemInfo.isMac ? new FileChooserDescriptor(false, true, false, false, false, false) { + @Override + public boolean isFileSelectable(VirtualFile file) { + return file.getName().endsWith(".app"); + } + } : FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor(); + + private static final ColumnInfo[] COLUMNS = {new EditableColumnInfo() { + @Override + public Class getColumnClass() { + return Boolean.class; + } + + @Override + public Boolean valueOf(ConfigurableWebBrowser item) { + return item.isActive(); + } + + @Override + public void setValue(ConfigurableWebBrowser item, Boolean value) { + item.setActive(value); + } + }, new EditableColumnInfo("Name") { + @Override + public String valueOf(ConfigurableWebBrowser item) { + return item.getName(); + } + + @Override + public void setValue(ConfigurableWebBrowser item, String value) { + item.setName(value); + } + }, new EditableColumnInfo("Family") { + @Override + public Class getColumnClass() { + return BrowserFamily.class; + } + + @Override + public BrowserFamily valueOf(ConfigurableWebBrowser item) { + return item.getFamily(); + } + + @Override + public void setValue(ConfigurableWebBrowser item, BrowserFamily value) { + item.setFamily(value); + } + + @Nullable + @Override + public TableCellRenderer getRenderer(ConfigurableWebBrowser item) { + return IconTableCellRenderer.ICONABLE; + } + + @Nullable + @Override + public TableCellEditor getEditor(ConfigurableWebBrowser item) { + return ComboBoxTableCellEditor.INSTANCE; + } + }, new EditableColumnInfo("Path") { + @Override + public String valueOf(ConfigurableWebBrowser item) { + return item.getPath(); + } + + @Override + public void setValue(ConfigurableWebBrowser item, String value) { + item.setPath(value); + } + + @Nullable + @Override + public TableCellEditor getEditor(ConfigurableWebBrowser item) { + return new LocalPathCellEditor().fileChooserDescriptor(APP_FILE_CHOOSER_DESCRIPTOR); + } + }}; + + private JPanel root; private JRadioButton useSystemDefaultBrowser; @@ -61,20 +139,11 @@ public class BrowserSettingsPanel { private TableModelEditor browsersEditor; - private final FileChooserDescriptor appFileChooserDescriptor; - public BrowserSettingsPanel() { defaultBrowserPanel.setBorder(IdeBorderFactory.createTitledBorder("Default Browser", true)); - appFileChooserDescriptor = SystemInfo.isMac ? - new FileChooserDescriptor(false, true, false, false, false, false) { - @Override - public boolean isFileSelectable(VirtualFile file) { - return file.getName().endsWith(".app"); - } - } : FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor(); alternativeBrowserPathField.addBrowseFolderListener(IdeBundle.message("title.select.path.to.browser"), null, null, - appFileChooserDescriptor); + APP_FILE_CHOOSER_DESCRIPTOR); if (BrowserUtil.canStartDefaultBrowser()) { ActionListener actionListener = new ActionListener() { @@ -100,84 +169,7 @@ public class BrowserSettingsPanel { } private void createUIComponents() { - browsersEditor = new TableModelEditor(WebBrowserManager.getInstance().getList(), new ColumnInfo[]{new EditableColumnInfo() { - @Override - public Class getColumnClass() { - return Boolean.class; - } - - @Override - public Boolean valueOf(ConfigurableWebBrowser item) { - return browsersEditor.getEffective(item).isActive(); - } - - @Override - public void setValue(ConfigurableWebBrowser item, Boolean value) { - if (value != item.isActive()) { - browsersEditor.getMutable(item).setActive(value); - } - } - }, new EditableColumnInfo("Name") { - @Override - public String valueOf(ConfigurableWebBrowser item) { - return browsersEditor.getEffective(item).getName(); - } - - @Override - public void setValue(ConfigurableWebBrowser item, String value) { - if (!value.equals(item.getName())) { - browsersEditor.getMutable(item).setName(value); - } - } - }, new EditableColumnInfo("Family") { - @Override - public Class getColumnClass() { - return BrowserFamily.class; - } - - @Override - public BrowserFamily valueOf(ConfigurableWebBrowser item) { - return browsersEditor.getEffective(item).getFamily(); - } - - @Override - public void setValue(ConfigurableWebBrowser item, BrowserFamily value) { - if (value != item.getFamily()) { - browsersEditor.getMutable(item).setFamily(value); - } - } - - @Nullable - @Override - public TableCellRenderer getRenderer(ConfigurableWebBrowser item) { - return IconTableCellRenderer.ICONABLE; - } - - @Nullable - @Override - public TableCellEditor getEditor(ConfigurableWebBrowser item) { - return ComboBoxTableCellEditor.INSTANCE; - } - }, new EditableColumnInfo("Path") { - @Override - public String valueOf(ConfigurableWebBrowser info) { - return browsersEditor.getEffective(info).getPath(); - } - - @Override - public void setValue(ConfigurableWebBrowser item, String value) { - String normalizedValue = StringUtil.nullize(value, true); - if (!Comparing.equal(normalizedValue, item.getPath())) { - browsersEditor.getMutable(item).setPath(normalizedValue); - } - } - - @Nullable - @Override - public TableCellEditor getEditor(ConfigurableWebBrowser item) { - return new LocalPathCellEditor().fileChooserDescriptor(appFileChooserDescriptor); - } - }}, new Function() { + browsersEditor = new TableModelEditor(WebBrowserManager.getInstance().getList(), COLUMNS, new Function() { @Override public ConfigurableWebBrowser fun(ConfigurableWebBrowser browser) { return new ConfigurableWebBrowser(browser.getId(), browser.getFamily(), browser.getName(), browser.getPath(), browser.isActive(), browser.getSpecificSettings()); diff --git a/xml/impl/src/com/intellij/ide/browsers/ConfigurableWebBrowser.java b/xml/impl/src/com/intellij/ide/browsers/ConfigurableWebBrowser.java index b191d188127d..38ef7e4f11ec 100644 --- a/xml/impl/src/com/intellij/ide/browsers/ConfigurableWebBrowser.java +++ b/xml/impl/src/com/intellij/ide/browsers/ConfigurableWebBrowser.java @@ -103,8 +103,10 @@ final class ConfigurableWebBrowser extends WebBrowser { ConfigurableWebBrowser browser = (ConfigurableWebBrowser)o; return id.equals(browser.id) && + family.equals(browser.family) && active == browser.active && - Comparing.equal(path, browser.path) && + Comparing.strEqual(name, browser.name) && + Comparing.strEqual(path, browser.path) && Comparing.equal(specificSettings, browser.specificSettings); } diff --git a/xml/impl/src/com/intellij/ide/browsers/TableModelEditor.java b/xml/impl/src/com/intellij/ide/browsers/TableModelEditor.java index a3ea1f779b9b..54cccb45b1aa 100644 --- a/xml/impl/src/com/intellij/ide/browsers/TableModelEditor.java +++ b/xml/impl/src/com/intellij/ide/browsers/TableModelEditor.java @@ -15,43 +15,44 @@ */ package com.intellij.ide.browsers; +import com.intellij.openapi.util.Comparing; import com.intellij.ui.TableSpeedSearch; import com.intellij.ui.TableUtil; import com.intellij.ui.ToolbarDecorator; import com.intellij.ui.table.TableView; import com.intellij.util.Function; +import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.ColumnInfo; import com.intellij.util.ui.ElementProducer; import com.intellij.util.ui.ListTableModel; import gnu.trove.THashMap; import gnu.trove.TObjectObjectProcedure; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.util.ArrayList; import java.util.List; -import java.util.Map; public class TableModelEditor implements ElementProducer { - private final List items; private final TableView table; - private final THashMap modifiedItems = new THashMap(); private final Function mutableFactory; private final Class itemClass; - private boolean isApplying; + private final MyListTableModel model; /** * source will be copied, passed list will not be used directly * itemClass must has empty constructor */ - public TableModelEditor(@NotNull List source, @NotNull ColumnInfo[] columns, @NotNull Function mutableFactory, Class itemClass) { + public TableModelEditor(@NotNull List items, @NotNull ColumnInfo[] columns, @NotNull Function mutableFactory, Class itemClass) { this.itemClass = itemClass; - items = new ArrayList(source); this.mutableFactory = mutableFactory; - table = new TableView(new ListTableModel(columns, items)); + model = new MyListTableModel(columns, new ArrayList(items), this); + table = new TableView(model); table.setStriped(true); new TableSpeedSearch(table); if (columns[0].getColumnClass() == Boolean.class && columns[0].getName().isEmpty()) { @@ -59,6 +60,95 @@ public class TableModelEditor implements ElementProducer { } } + private static final class MyListTableModel extends ListTableModel { + private final List items; + private final TableModelEditor editor; + private final THashMap modifiedToOriginal = new THashMap(); + + public MyListTableModel(ColumnInfo[] columns, List items, TableModelEditor editor) { + super(columns, items); + + this.items = items; + this.editor = editor; + } + + @Override + public void setItems(@NotNull List items) { + throw new IncorrectOperationException(); + } + + @Override + public void setValueAt(Object newValue, int rowIndex, int columnIndex) { + if (rowIndex < getRowCount()) { + @SuppressWarnings("unchecked") + ColumnInfo column = (ColumnInfo)getColumnInfos()[columnIndex]; + T item = getItem(rowIndex); + Object oldValue = column.valueOf(item); + if (column.getColumnClass() == String.class + ? !Comparing.strEqual(((String)oldValue), ((String)newValue)) + : !Comparing.equal(oldValue, newValue)) { + + T mutable; + if (modifiedToOriginal.containsKey(item)) { + mutable = item; + } + else { + mutable = editor.mutableFactory.fun(item); + modifiedToOriginal.put(mutable, item); + items.set(rowIndex, mutable); + } + + column.setValue(mutable, newValue); + } + } + } + + public boolean isModified(@NotNull List oldItems) { + if (items.size() == oldItems.size()) { + for (int i = 0, size = items.size(); i < size; i++) { + if (!items.get(i).equals(oldItems.get(i))) { + return true; + } + } + } + else { + return true; + } + + return false; + } + + @NotNull + public List apply() { + if (modifiedToOriginal.isEmpty()) { + return items; + } + + @SuppressWarnings("unchecked") + final ColumnInfo[] columns = getColumnInfos(); + modifiedToOriginal.forEachEntry(new TObjectObjectProcedure() { + @Override + public boolean execute(T newItem, @Nullable T item) { + if (item == null) { + // it is added item, we don't need to sync + return true; + } + + for (ColumnInfo column : columns) { + if (column.isCellEditable(newItem)) { + column.setValue(item, column.valueOf(newItem)); + } + } + items.set(ContainerUtil.indexOfIdentity(items, newItem), item); + return true; + } + }); + + modifiedToOriginal.clear(); + return items; + } + } + public abstract static class EditableColumnInfo extends ColumnInfo { public EditableColumnInfo(@NotNull String name) { super(name); @@ -82,7 +172,9 @@ public class TableModelEditor implements ElementProducer { @Override public T createElement() { try { - return itemClass.newInstance(); + T item = itemClass.newInstance(); + model.modifiedToOriginal.put(item, null); + return item; } catch (InstantiationException e) { throw new RuntimeException(e); @@ -97,76 +189,16 @@ public class TableModelEditor implements ElementProducer { return true; } - @NotNull - public T getEffective(@NotNull T item) { - T mutable = isApplying || modifiedItems.isEmpty() ? null : modifiedItems.get(item); - return mutable == null ? item : mutable; - } - - @NotNull - public T getMutable(@NotNull T item) { - if (isApplying) { - return item; - } - - T mutable = modifiedItems.get(item); - if (mutable == null) { - mutable = mutableFactory.fun(item); - modifiedItems.put(item, mutable); - } - return mutable; - } - public boolean isModified(@NotNull List oldItems) { - if (!modifiedItems.isEmpty()) { - for (Map.Entry entry : modifiedItems.entrySet()) { - if (entry.getValue().equals(entry.getKey())) { - return true; - } - } - } - - // is order changed or new items added? - if (items.size() == oldItems.size()) { - for (int i = 0, size = items.size(); i < size; i++) { - if (items.get(i) != oldItems.get(i)) { - return true; - } - } - } - else { - return true; - } - - return false; + return model.isModified(oldItems); } @NotNull public List apply() { - if (!modifiedItems.isEmpty()) { - isApplying = true; - - @SuppressWarnings("unchecked") - final ColumnInfo[] columns = ((ListTableModel)table.getModel()).getColumnInfos(); - modifiedItems.forEachEntry(new TObjectObjectProcedure() { - @Override - public boolean execute(T item, T newItem) { - for (ColumnInfo column : columns) { - if (column.isCellEditable(item)) { - column.setValue(item, column.valueOf(newItem)); - } - } - return true; - } - }); - - isApplying = false; - modifiedItems.clear(); - } - return items; + return model.apply(); } public void clear() { - modifiedItems.clear(); + model.modifiedToOriginal.clear(); } } \ No newline at end of file