blob: 2810c22e0834f84973cac7a15810fe10e98363f6 [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* 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.android.tools.idea.updater.configure;
import com.android.tools.idea.sdk.LogWrapper;
import com.android.tools.idea.sdk.SdkState;
import com.android.tools.idea.sdk.remote.RemoteSdk;
import com.android.tools.idea.sdk.remote.internal.sources.*;
import com.android.utils.StdLogger;
import com.google.common.base.Objects;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.util.ui.ColumnInfo;
import com.intellij.util.ui.EditableModel;
import com.intellij.util.ui.ListTableModel;
import com.intellij.util.ui.table.IconTableCellRenderer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.table.TableCellRenderer;
import java.util.*;
/**
* Table model representing an {@link SdkSources}. Sources can be added, deleted, enabled, and disabled.
*/
class SourcesTableModel extends ListTableModel<SourcesTableModel.Row> implements EditableModel {
private SdkSources mySources;
private Map<String, SdkSource> myInitialItems = Maps.newHashMap();
private SdkState mySdkState;
SourcesTableModel() {
super();
setColumnInfos(new ColumnInfo[]{new ColumnInfo<Row, Boolean>("Enabled") {
@Nullable
@Override
public Boolean valueOf(Row row) {
return row.myEnabled;
}
@Override
public int getWidth(JTable table) {
return 60;
}
@Override
public Class getColumnClass() {
return Boolean.class;
}
@Override
public boolean isCellEditable(Row row) {
return Strings.isNullOrEmpty(row.mySource.getFetchError());
}
@Override
public void setValue(Row row, Boolean value) {
row.myEnabled = value;
row.mySource.setEnabled(value); // source enablement changes are saved right away so they can be reflected in the other tabs
myUrlEnabledMap.put(row.mySource.getUrl(), value);
mySources.notifyChangeListeners();
}
@Nullable
@Override
public TableCellRenderer getRenderer(final Row row) {
String error = row.mySource.getFetchError();
if (!Strings.isNullOrEmpty(error)) {
return new IconTableCellRenderer<Boolean>() {
@Nullable
@Override
protected Icon getIcon(@NotNull Boolean value, JTable table, int row) {
return AllIcons.General.Error;
}
@Override
public String getText() {
return null;
}
@Override
public String getToolTipText() {
return row.mySource.getFetchError();
}
@Override
public int getHorizontalAlignment() {
return SwingConstants.CENTER;
}
};
}
return super.getRenderer(row);
}
}, new ColumnInfo<Row, String>("Name") {
@Nullable
@Override
public String valueOf(Row r) {
return r.mySource.getUiName();
}
}, new ColumnInfo<Row, String>("URL") {
@Nullable
@Override
public String valueOf(Row r) {
return r.mySource.getUrl();
}
}});
}
public void setSourceEnabled(int i, boolean enabled) {
Row r = getItem(i);
r.myEnabled = enabled;
myUrlEnabledMap.put(r.mySource.getUrl(), enabled);
fireTableRowsUpdated(i, i);
mySources.notifyChangeListeners();
}
public void setSdkState(SdkState state) {
mySdkState = state;
mySources = state.getRemoteSdk().fetchSources(RemoteSdk.DEFAULT_EXPIRATION_PERIOD_MS, new LogWrapper(Logger.getInstance(getClass())));
for (SdkSource s : mySources.getAllSources()) {
myInitialItems.put(s.getUrl(), s);
}
refreshSources();
}
private Map<String, Boolean> myUrlEnabledMap = Maps.newHashMap();
public void refreshSources() {
ArrayList<Row> items = Lists.newArrayList();
for (SdkSource source : mySources.getAllSources()) {
Boolean enabled = myUrlEnabledMap.get(source.getUrl());
if (enabled == null) {
enabled = source.isEnabled();
myUrlEnabledMap.put(source.getUrl(), enabled);
}
items.add(new Row(source, enabled));
}
setItems(items);
}
public void editRow(int index) {
Row r = getRowValue(index);
EditSourceDialog input = showEditDialog(r.mySource);
if (input.isOK()) {
removeRow(index);
createSource(input.getUrl(), input.getUiName());
}
}
@Override
public void addRow() {
EditSourceDialog input = showEditDialog(null);
if (input.isOK()) {
createSource(input.getUrl(), input.getUiName());
}
}
@NotNull
private EditSourceDialog showEditDialog(SdkSource source) {
EditSourceDialog input = new EditSourceDialog(mySources, source);
input.show();
return input;
}
private void createSource(String url, String uiName) {
SdkSource newSource;
// use url suffix to decide whether this is a SysImg or Addon;
// see SdkSources.loadUserAddons() for another check like this
if (url.endsWith(SdkSysImgConstants.URL_DEFAULT_FILENAME)) {
newSource = new SdkSysImgSource(url, uiName);
}
else {
newSource = new SdkAddonSource(url, uiName);
}
mySources.add(SdkSourceCategory.USER_ADDONS, newSource);
mySources.notifyChangeListeners();
}
@Override
public void removeRow(int idx) {
mySources.remove(getRowValue(idx).mySource);
super.removeRow(idx);
mySources.notifyChangeListeners();
}
@Override
public void exchangeRows(int oldIndex, int newIndex) {}
@Override
public boolean canExchangeRows(int oldIndex, int newIndex) {
return false;
}
public boolean isEditable(int row) {
return Sets.newHashSet(mySources.getSources(SdkSourceCategory.USER_ADDONS)).contains(getRowValue(row).mySource);
}
public void reset() {
if (isSourcesModified()) {
mySources.loadUserAddons(new StdLogger(StdLogger.Level.WARNING));
}
for (Row row : getItems()) {
row.myEnabled = row.mySource.isEnabled();
}
refreshSources();
}
public boolean isSourcesModified() {
if (getItems().size() != myInitialItems.size()) {
return true;
}
for (Row row : getItems()) {
SdkSource orig = myInitialItems.get(row.mySource.getUrl());
if (orig == null || !Objects.equal(orig.getUiName(), row.mySource.getUiName()) || (orig.isEnabled() != row.myEnabled)) {
return true;
}
}
return false;
}
public void save() {
if (isSourcesModified()) {
mySources.saveUserAddons(new StdLogger(StdLogger.Level.WARNING));
for (Row row : getItems()) {
row.mySource.setEnabled(row.myEnabled);
}
}
}
protected static class Row implements SdkUpdaterConfigPanel.MultiStateRow {
SdkSource mySource;
boolean myEnabled;
public Row(SdkSource source, boolean enabled) {
mySource = source;
myEnabled = enabled;
}
@Override
public void cycleState() {
myEnabled = !myEnabled;
}
}
}