/*
* Copyright 2003-2012 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 jetbrains.mps.idea.core.ui;
import com.intellij.ide.util.ChooseElementsDialog;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.ui.AnActionButton;
import com.intellij.ui.AnActionButtonRunnable;
import com.intellij.ui.ColoredTableCellRenderer;
import com.intellij.ui.JBColor;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.ui.SpeedSearchBase;
import com.intellij.ui.TableUtil;
import com.intellij.ui.ToolbarDecorator;
import com.intellij.ui.table.JBTable;
import jetbrains.mps.smodel.ModelAccess;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import javax.swing.table.TableCellRenderer;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public abstract class MpsElementsTable<T> {
private final Border NO_FOCUS_BORDER = BorderFactory.createEmptyBorder(1, 1, 1, 1);
private MpsElementsTableModel<T> myElementsTableModel;
private JBTable myElementsTable;
private boolean myAddRemoveNeeded;
protected MpsElementsTable(boolean addRemoveNeeded) {
myAddRemoveNeeded = addRemoveNeeded;
}
public JComponent createComponent() {
myElementsTableModel = new MpsElementsTableModel<>(getComparator(), getRendererClass(), getColumnTitle());
JBTable table = new JBTable(myElementsTableModel);
table.setShowGrid(false);
table.setDragEnabled(false);
table.setShowHorizontalLines(false);
table.setShowVerticalLines(false);
table.setIntercellSpacing(new Dimension(0, 0));
table.setBorder(new LineBorder(JBColor.border()));
table.setDefaultRenderer(getRendererClass(), createDefaultRenderer());
table.getSelectionModel().setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
myElementsTable = table;
new SpeedSearchBase<JBTable>(myElementsTable) {
public int getSelectedIndex() {
return myElementsTable.getSelectedRow();
}
@Override
protected int convertIndexToModel(int viewIndex) {
return myElementsTable.convertRowIndexToModel(viewIndex);
}
public Object[] getAllElements() {
final int count = myElementsTableModel.getRowCount();
Object[] elements = new Object[count];
for (int idx = 0; idx < count; idx++) {
elements[idx] = myElementsTableModel.getValueAt(0, idx);
}
return elements;
}
public String getElementText(Object element) {
return getText((T) element);
}
public void selectElement(Object element, String selectedText) {
final int count = myElementsTableModel.getRowCount();
for (int row = 0; row < count; row++) {
if (element.equals(myElementsTableModel.getValueAt(0, row))) {
final int viewRow = myElementsTable.convertRowIndexToView(row);
myElementsTable.getSelectionModel().setSelectionInterval(viewRow, viewRow);
TableUtil.scrollSelectionToVisible(myElementsTable);
break;
}
}
}
};
if (!myAddRemoveNeeded) {
return myElementsTable;
}
ToolbarDecorator decorator = ToolbarDecorator.createDecorator(myElementsTable);
decorator.setAddAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton anActionButton) {
ModelAccess.instance().runReadInEDT(new Runnable() {
@Override
public void run() {
final java.util.List<T> allElements = getAllVisibleElements();
allElements.removeAll(getElements());
Collections.sort(allElements, getComparator());
ApplicationManager.getApplication().invokeLater(() -> {
ChooseElementsDialog<T> chooseElementsDialog = new ChooseElementsDialog<T>(myElementsTable, allElements, getChooserMessage()) {
@Override
protected String getItemText(T item) {
return getText(item);
}
@Override
protected Icon getItemIcon(T item) {
return getIcon(item);
}
};
chooseElementsDialog.show();
Set<T> elementsToAdd = new HashSet<>(chooseElementsDialog.getChosenElements());
doAddElements(elementsToAdd);
});
}
});
}
}).setRemoveAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton anActionButton) {
TableUtil.removeSelectedItems(myElementsTable);
myElementsTableModel.fireTableDataChanged();
}
});
return postDecoratePanel(decorator.createPanel());
}
protected TableCellRenderer createDefaultRenderer() {
return new ColoredTableCellRenderer() {
@Override
protected void customizeCellRenderer(JTable table, Object value, boolean selected, boolean hasFocus, int row, int column) {
setPaintFocusBorder(false);
setFocusBorderAroundIcon(true);
setBorder(NO_FOCUS_BORDER);
if (value != null) {
T tableItem = (T) value;
setIcon(MpsElementsTable.this.getIcon(tableItem));
append(getText(tableItem), getTextAttributes(tableItem));
setToolTipText(MpsElementsTable.this.getToolTipText(tableItem));
}
}
};
}
protected abstract String getText(T element);
protected abstract Icon getIcon(T element);
// should be executed only inside MPS model read
protected abstract List<T> getAllVisibleElements();
protected abstract Comparator<T> getComparator();
protected abstract Class<T> getRendererClass();
protected abstract String getChooserMessage();
protected void doAddElements(Set<T> elementsToAdd) {
myElementsTableModel.addElements(elementsToAdd);
myElementsTableModel.fireTableDataChanged();
ListSelectionModel selectionModel = myElementsTable.getSelectionModel();
if (!elementsToAdd.isEmpty()) {
selectionModel.clearSelection();
for (int i = 0; i < myElementsTableModel.getRowCount(); i++) {
if (elementsToAdd.contains(myElementsTableModel.getValueAt(i, 0))) {
selectionModel.addSelectionInterval(i, i);
}
}
}
}
protected JPanel postDecoratePanel(JPanel panel) {
panel.setBorder(null);
return panel;
}
protected String getColumnTitle() {
return null;
}
public List<T> getElements() {
return myElementsTableModel.getElements();
}
public void setElements(List<T> elements) {
myElementsTableModel.setElements(elements);
myElementsTableModel.fireTableDataChanged();
if (myElementsTable.getRowCount() > 0) {
myElementsTable.getSelectionModel().setSelectionInterval(0, 0);
}
}
public boolean isModified(List<T> elements) {
List<T> sortedLanguagesList = new ArrayList<>(elements);
Collections.sort(sortedLanguagesList, getComparator());
return !getElements().equals(sortedLanguagesList);
}
protected SimpleTextAttributes getTextAttributes(T element) {
return SimpleTextAttributes.REGULAR_ATTRIBUTES;
}
protected String getToolTipText(T element) {
return null;
}
}