mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
continue WEB-2093: fix editing
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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<ConfigurableWebBrowser, Boolean>() {
|
||||
@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<ConfigurableWebBrowser, String>("Name") {
|
||||
@Override
|
||||
public String valueOf(ConfigurableWebBrowser item) {
|
||||
return item.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(ConfigurableWebBrowser item, String value) {
|
||||
item.setName(value);
|
||||
}
|
||||
}, new EditableColumnInfo<ConfigurableWebBrowser, BrowserFamily>("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<ConfigurableWebBrowser, String>("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<ConfigurableWebBrowser> 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<ConfigurableWebBrowser>(WebBrowserManager.getInstance().getList(), new ColumnInfo[]{new EditableColumnInfo<ConfigurableWebBrowser, Boolean>() {
|
||||
@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<ConfigurableWebBrowser, String>("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<ConfigurableWebBrowser, BrowserFamily>("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<ConfigurableWebBrowser, String>("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<ConfigurableWebBrowser, ConfigurableWebBrowser>() {
|
||||
browsersEditor = new TableModelEditor<ConfigurableWebBrowser>(WebBrowserManager.getInstance().getList(), COLUMNS, new Function<ConfigurableWebBrowser, ConfigurableWebBrowser>() {
|
||||
@Override
|
||||
public ConfigurableWebBrowser fun(ConfigurableWebBrowser browser) {
|
||||
return new ConfigurableWebBrowser(browser.getId(), browser.getFamily(), browser.getName(), browser.getPath(), browser.isActive(), browser.getSpecificSettings());
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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<T> implements ElementProducer<T> {
|
||||
private final List<T> items;
|
||||
private final TableView<T> table;
|
||||
|
||||
private final THashMap<T, T> modifiedItems = new THashMap<T, T>();
|
||||
private final Function<T, T> mutableFactory;
|
||||
private final Class<T> itemClass;
|
||||
|
||||
private boolean isApplying;
|
||||
private final MyListTableModel<T> model;
|
||||
|
||||
/**
|
||||
* source will be copied, passed list will not be used directly
|
||||
* itemClass must has empty constructor
|
||||
*/
|
||||
public TableModelEditor(@NotNull List<T> source, @NotNull ColumnInfo[] columns, @NotNull Function<T, T> mutableFactory, Class<T> itemClass) {
|
||||
public TableModelEditor(@NotNull List<T> items, @NotNull ColumnInfo[] columns, @NotNull Function<T, T> mutableFactory, Class<T> itemClass) {
|
||||
this.itemClass = itemClass;
|
||||
items = new ArrayList<T>(source);
|
||||
this.mutableFactory = mutableFactory;
|
||||
|
||||
table = new TableView<T>(new ListTableModel<T>(columns, items));
|
||||
model = new MyListTableModel<T>(columns, new ArrayList<T>(items), this);
|
||||
table = new TableView<T>(model);
|
||||
table.setStriped(true);
|
||||
new TableSpeedSearch(table);
|
||||
if (columns[0].getColumnClass() == Boolean.class && columns[0].getName().isEmpty()) {
|
||||
@@ -59,6 +60,95 @@ public class TableModelEditor<T> implements ElementProducer<T> {
|
||||
}
|
||||
}
|
||||
|
||||
private static final class MyListTableModel<T> extends ListTableModel<T> {
|
||||
private final List<T> items;
|
||||
private final TableModelEditor<T> editor;
|
||||
private final THashMap<T, T> modifiedToOriginal = new THashMap<T, T>();
|
||||
|
||||
public MyListTableModel(ColumnInfo[] columns, List<T> items, TableModelEditor<T> editor) {
|
||||
super(columns, items);
|
||||
|
||||
this.items = items;
|
||||
this.editor = editor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setItems(@NotNull List<T> items) {
|
||||
throw new IncorrectOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValueAt(Object newValue, int rowIndex, int columnIndex) {
|
||||
if (rowIndex < getRowCount()) {
|
||||
@SuppressWarnings("unchecked")
|
||||
ColumnInfo<T, Object> column = (ColumnInfo<T, Object>)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<T> 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<T> apply() {
|
||||
if (modifiedToOriginal.isEmpty()) {
|
||||
return items;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
final ColumnInfo<T, Object>[] columns = getColumnInfos();
|
||||
modifiedToOriginal.forEachEntry(new TObjectObjectProcedure<T, T>() {
|
||||
@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<T, Object> 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<Item, Aspect> extends ColumnInfo<Item, Aspect> {
|
||||
public EditableColumnInfo(@NotNull String name) {
|
||||
super(name);
|
||||
@@ -82,7 +172,9 @@ public class TableModelEditor<T> implements ElementProducer<T> {
|
||||
@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<T> implements ElementProducer<T> {
|
||||
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<T> oldItems) {
|
||||
if (!modifiedItems.isEmpty()) {
|
||||
for (Map.Entry<T, T> 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<T> apply() {
|
||||
if (!modifiedItems.isEmpty()) {
|
||||
isApplying = true;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
final ColumnInfo<T, Object>[] columns = ((ListTableModel)table.getModel()).getColumnInfos();
|
||||
modifiedItems.forEachEntry(new TObjectObjectProcedure<T, T>() {
|
||||
@Override
|
||||
public boolean execute(T item, T newItem) {
|
||||
for (ColumnInfo<T, Object> 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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user