/* * Copyright 2000-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 com.intellij.ui.table; import com.intellij.ui.GuiUtils; import com.intellij.ui.TableUtil; import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.ColumnInfo; import com.intellij.util.ui.ListTableModel; import com.intellij.util.ui.SortableColumnModel; import com.intellij.util.ui.TableViewModel; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.event.TableModelEvent; import javax.swing.table.*; import java.awt.*; import java.util.Collection; import java.util.Collections; import java.util.List; public class TableView extends BaseTableView implements ItemsProvider, SelectionProvider { public TableView() { this(new ListTableModel(ColumnInfo.EMPTY_ARRAY)); } public TableView(final ListTableModel model) { super(model); setModelAndUpdateColumns(model); } @Override public void setModel(@NotNull final TableModel dataModel) { assert dataModel instanceof SortableColumnModel : "SortableColumnModel required"; super.setModel(dataModel); } /** * use {@link #setModelAndUpdateColumns(com.intellij.util.ui.ListTableModel)} instead * @param model */ @Deprecated public void setModel(final ListTableModel model) { setModelAndUpdateColumns(model); } public void setModelAndUpdateColumns(final ListTableModel model) { super.setModel(model); createDefaultColumnsFromModel(); updateColumnSizes(); } public ListTableModel getListTableModel() { return (ListTableModel)super.getModel(); } @Override public TableCellRenderer getCellRenderer(int row, int column) { final ColumnInfo columnInfo = getListTableModel().getColumnInfos()[convertColumnIndexToModel(column)]; final Item item = getRow(row); final TableCellRenderer renderer = columnInfo.getCustomizedRenderer(item, columnInfo.getRenderer(item)); if (renderer == null) { return super.getCellRenderer(row, column); } else { return renderer; } } @Override public void tableChanged(TableModelEvent e) { if (isEditing()) getCellEditor().cancelCellEditing(); super.tableChanged(e); } public void setSelection(Collection selection) { clearSelection(); for (Object aSelection : selection) { addSelection(aSelection); } } public void updateColumnSizes() { final JTableHeader header = getTableHeader(); final TableCellRenderer defaultRenderer = header == null? null : header.getDefaultRenderer(); final RowSorter sorter = getRowSorter(); final RowSorter.SortKey sortKey = sorter == null ? null : ContainerUtil.getFirstItem(sorter.getSortKeys()); ColumnInfo[] columnInfos = getListTableModel().getColumnInfos(); TableColumnModel columnModel = getColumnModel(); int visibleColumnCount = columnModel.getColumnCount(); int[] sizeMode = new int[visibleColumnCount]; int[] headers = new int[visibleColumnCount]; int[] widths = new int[visibleColumnCount]; int allColumnWidth = 0; int allColumnCurrent = 0; int varCount = 0; Icon sortIcon = UIManager.getIcon("Table.ascendingSortIcon"); // calculate for (int i = 0; i < visibleColumnCount; i++) { final TableColumn column = columnModel.getColumn(i); final ColumnInfo columnInfo = columnInfos[column.getModelIndex()]; TableCellRenderer columnHeaderRenderer = column.getHeaderRenderer(); if (columnHeaderRenderer == null) { columnHeaderRenderer = defaultRenderer; } final Component headerComponent = columnHeaderRenderer == null? null : columnHeaderRenderer.getTableCellRendererComponent(this, column.getHeaderValue(), false, false, 0, i); if (headerComponent != null) { headers[i] = headerComponent.getPreferredSize().width; // add sort icon width if (sorter != null && columnInfo.isSortable() && sortIcon != null && (sortKey == null || sortKey.getColumn() != i)) { headers[i] += sortIcon.getIconWidth() + (headerComponent instanceof JLabel? ((JLabel)headerComponent).getIconTextGap() : 0); } } final String maxStringValue; final String preferredValue; if (columnInfo.getWidth(this) > 0) { sizeMode[i] = 1; int width = columnInfo.getWidth(this); widths[i] = width; } else if ((maxStringValue = columnInfo.getMaxStringValue()) != null) { sizeMode[i] = 2; widths[i] = getFontMetrics(getFont()).stringWidth(maxStringValue) + columnInfo.getAdditionalWidth(); varCount ++; } else if ((preferredValue = columnInfo.getPreferredStringValue()) != null) { sizeMode[i] = 3; widths[i] = getFontMetrics(getFont()).stringWidth(preferredValue) + columnInfo.getAdditionalWidth(); varCount ++; } allColumnWidth += widths[i]; allColumnCurrent += column.getPreferredWidth(); } allColumnWidth = Math.max(allColumnWidth, allColumnCurrent); // apply: distribute available space between resizable columns // and make sure that header will fit as well int viewWidth = getParent() != null? getParent().getWidth() : getWidth(); double gold = 0.5 * (3 - Math.sqrt(5)); int addendum = varCount == 0 || viewWidth < allColumnWidth ? 0 : (int)((allColumnWidth < gold * viewWidth ? gold * viewWidth : allColumnWidth < (1 - gold) * viewWidth ? (1 - gold) * viewWidth : viewWidth) - allColumnWidth) / varCount; for (int i = 0 ; i < visibleColumnCount; i++) { TableColumn column = columnModel.getColumn(i); int width = widths[i]; if (sizeMode[i] == 1) { column.setMaxWidth(width); column.setPreferredWidth(width); column.setMinWidth(width); } else if (sizeMode[i] == 2) { // do not shrink columns width = Math.max(column.getPreferredWidth(), Math.max(width + addendum, headers[i])); column.setPreferredWidth(width); column.setMaxWidth(width); } else if (sizeMode[i] == 3) { // do not shrink columns width = Math.max(column.getPreferredWidth(), Math.max(width + addendum, headers[i])); column.setPreferredWidth(width); } } } @Override public Collection getSelection() { return getSelectedObjects(); } @Nullable public Item getSelectedObject() { final int row = getSelectedRow(); ListTableModel model = getListTableModel(); return row >= 0 && row < model.getRowCount() ? model.getRowValue(convertRowIndexToModel(row)) : null; } @NotNull public List getSelectedObjects() { ListSelectionModel selectionModel = getSelectionModel(); int minSelectionIndex = selectionModel.getMinSelectionIndex(); int maxSelectionIndex = selectionModel.getMaxSelectionIndex(); if (minSelectionIndex == -1 || maxSelectionIndex == -1) { return Collections.emptyList(); } List result = new SmartList(); ListTableModel model = getListTableModel(); for (int i = minSelectionIndex; i <= maxSelectionIndex; i++) { if (selectionModel.isSelectedIndex(i)) { int modelIndex = convertRowIndexToModel(i); if (modelIndex >= 0 && modelIndex < model.getRowCount()) { result.add(model.getRowValue(modelIndex)); } } } return result; } @Override public void addSelection(Object item) { @SuppressWarnings("unchecked") int index = getListTableModel().indexOf((Item)item); if (index < 0) { return; } getSelectionModel().addSelectionInterval(convertRowIndexToView(index), convertRowIndexToView(index)); // fix cell selection case getColumnModel().getSelectionModel().addSelectionInterval(0, getColumnCount()-1); } @Override public TableCellEditor getCellEditor(int row, int column) { @SuppressWarnings("unchecked") TableCellEditor editor = getListTableModel().getColumnInfos()[convertColumnIndexToModel(column)].getEditor(getRow(row)); return editor == null ? super.getCellEditor(row, column) : editor; } @Override public List getItems() { return getListTableModel().getItems(); } public Item getRow(int row) { return getListTableModel().getRowValue(convertRowIndexToModel(row)); } public void setMinRowHeight(int i) { setRowHeight(Math.max(i, getRowHeight())); } public JTable getComponent() { return this; } public TableViewModel getTableViewModel() { return getListTableModel(); } public void stopEditing() { TableUtil.stopEditing(this); } @Override protected void createDefaultEditors() { super.createDefaultEditors(); //noinspection unchecked defaultEditorsByColumnClass.put(String.class, new UIDefaults.LazyValue() { @Override public Object createValue(UIDefaults table) { return new DefaultCellEditor(GuiUtils.createUndoableTextField()); } }); } }