/*
* Copyright (C) 2014 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.sdk.wizard;
import com.android.annotations.NonNull;
import com.android.sdklib.internal.repository.IListDescription;
import com.android.sdklib.repository.local.LocalPkgInfo;
import com.android.sdklib.repository.remote.RemotePkgInfo;
import com.android.utils.Pair;
import com.intellij.openapi.Disposable;
import com.intellij.ui.BooleanTableCellEditor;
import com.intellij.ui.BooleanTableCellRenderer;
import com.intellij.util.ui.ColumnInfo;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
/**
* Model for confirmation step table.
* <p/>
* Inspiration source: PluginTableModel.
*/
public class SmwConfirmationTableModel extends AbstractTableModel implements Disposable {
private boolean myIsDisposed;
private final ColumnInfo[] myColumns;
private final List<LineInfo> myLines = new ArrayList<LineInfo>();
public SmwConfirmationTableModel(ColumnInfo... columns) {
myColumns = columns;
}
@Override
public int getRowCount() {
return myLines.size();
}
@Override
public int getColumnCount() {
return myColumns.length;
}
@NonNull
public ColumnInfo getColumnInfo(int columnIndex) {
return myColumns[columnIndex];
}
@NonNull
public LineInfo getObjectAt(int rowIndex) {
return myLines.get(rowIndex);
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
//noinspection ConstantConditions,unchecked
return myColumns[columnIndex].valueOf(myLines.get(rowIndex));
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
//noinspection unchecked
return myColumns[columnIndex].isCellEditable(myLines.get(rowIndex));
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
//noinspection unchecked
myColumns[columnIndex].setValue(myLines.get(rowIndex), aValue);
for (int i = 0; i < myColumns.length; i++) {
fireTableCellUpdated(rowIndex, i);
}
}
public void fillModel(List<Pair<SmwSelectionAction, IListDescription>> selectedActions) {
myLines.clear();
// TODO compute install/updates dependencies.
// also it's nice to sort the selection by placing dependencies first.
// right now just use the selection as-is.
boolean needHeader = true;
for (Pair<SmwSelectionAction, IListDescription> action : selectedActions) {
if (action.getFirst() != SmwSelectionAction.UPDATE &&
action.getFirst() != SmwSelectionAction.INSTALL) {
continue;
}
if (needHeader) {
myLines.add(new LineInfo("===[ Packages to install/update ]===="));
needHeader = false;
}
if (action.getFirst() == SmwSelectionAction.UPDATE) {
myLines.add(new LineInfo((LocalPkgInfo)action.getSecond(), LineType.UPDATE));
} else {
myLines.add(new LineInfo((RemotePkgInfo)action.getSecond()));
}
}
// Find all removable items and list them last
needHeader = true;
for (Pair<SmwSelectionAction, IListDescription> action : selectedActions) {
if (action.getFirst() != SmwSelectionAction.REMOVE) {
continue;
}
if (needHeader) {
myLines.add(new LineInfo("===[ Packages to remove ]===="));
needHeader = false;
}
myLines.add(new LineInfo((LocalPkgInfo)action.getSecond(), LineType.REMOVE));
}
fireTableDataChanged();
}
public void fillModel(@NonNull List<LocalPkgInfo> removeList,
@NonNull List<RemotePkgInfo> installList) {
myLines.clear();
fireTableDataChanged();
}
@Override
public void dispose() {
myIsDisposed = true;
}
// ----
enum LineType {
HEADER,
REMOVE,
UPDATE,
INSTALL
}
static class LineInfo {
private LineType myType;
private String myHeader;
private LocalPkgInfo myRemovedPkg;
private LocalPkgInfo myUpdatePkg;
private RemotePkgInfo myInstallNewPkg;
private boolean myAccept;
public LineInfo(@NonNull String header) {
myType = LineType.HEADER;
myHeader = header;
}
@SuppressWarnings("ConstantConditions")
public LineInfo(@NonNull LocalPkgInfo info, LineType type) {
assert type == LineType.REMOVE || type == LineType.UPDATE;
myType = type;
if (type == LineType.REMOVE) {
myRemovedPkg = info;
} else if (type == LineType.UPDATE) {
myUpdatePkg = info;
}
}
public LineInfo(@NonNull RemotePkgInfo info) {
myType = LineType.INSTALL;
myInstallNewPkg = info;
}
@NonNull
public LineType getType() {
return myType;
}
@Nullable
public LocalPkgInfo getRemovedPkg() {
return myRemovedPkg;
}
@Nullable
public LocalPkgInfo getUpdatePkg() {
return myUpdatePkg;
}
@Nullable
public RemotePkgInfo getInstallNewPkg() {
return myInstallNewPkg;
}
}
// ------------
public static class LabelColumnInfo extends ColumnInfo<LineInfo, String> {
private SmwConfirmationTableModel myModel;
public LabelColumnInfo(@NonNull String name) {
super(name);
}
public void setModel(@NonNull SmwConfirmationTableModel model) {
myModel = model;
}
@Override
public String valueOf(LineInfo item) {
// TODO placeholder.
switch (item.myType) {
case HEADER:
return item.myHeader;
case REMOVE:
return "Remove " + item.myRemovedPkg.getListDescription();
case INSTALL:
return "New " + item.myInstallNewPkg.getListDescription();
case UPDATE:
assert item.myUpdatePkg.getUpdate() != null;
return "Update to " + item.myUpdatePkg.getUpdate().getListDescription();
}
return ""; // should not happen
}
@Override
public boolean isCellEditable(LineInfo item) {
return false;
}
@Nullable
@Override
public TableCellRenderer getRenderer(LineInfo item) {
return new DefaultTableCellRenderer();
}
}
// ------------
public static class InstallColumnInfo extends ColumnInfo<LineInfo, Boolean> {
public InstallColumnInfo(@NonNull String name) {
super(name);
}
@Override
public Boolean valueOf(LineInfo item) {
return item.myAccept;
}
@Override
public boolean isCellEditable(LineInfo item) {
return item.myType != LineType.HEADER;
}
@Override
public Class getColumnClass() {
return Boolean.class;
}
@Override
public TableCellEditor getEditor(LineInfo item) {
return new BooleanTableCellEditor();
}
@Nullable
@Override
public TableCellRenderer getRenderer(LineInfo o) {
return new BooleanTableCellRenderer() {
@Override
public Component getTableCellRendererComponent(JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column) {
return super.getTableCellRendererComponent(table, value == null ? Boolean.TRUE : value, isSelected, hasFocus, row, column);
}
};
}
@Override
public int getWidth(JTable table) {
return new JCheckBox().getPreferredSize().width;
}
@Override
public void setValue(LineInfo item, Boolean value) {
item.myAccept = value.booleanValue();
super.setValue(item, value);
}
}
}