/*
* Copyright 2000-2010 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.components;
import com.intellij.ide.DataManager;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.*;
import com.intellij.util.NotNullFunction;
import com.intellij.util.ui.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.util.Collection;
/**
* @author Anton Makeev
* @author Konstantin Bulenkov
*/
public class JBList<E> extends JList<E> implements ComponentWithEmptyText, ComponentWithExpandableItems<Integer> {
@NotNull
private StatusText myEmptyText;
@NotNull
private ExpandableItemsHandler<Integer> myExpandableItemsHandler;
@Nullable private AsyncProcessIcon myBusyIcon;
private boolean myBusy;
public JBList() {
init();
}
public JBList(@NotNull ListModel<E> dataModel) {
super(dataModel);
init();
}
@SafeVarargs
public JBList(@NotNull E... listData) {
super(createDefaultListModel(listData));
init();
}
@NotNull
@SafeVarargs
public static <E> DefaultListModel<E> createDefaultListModel(@NotNull E... items) {
final DefaultListModel<E> model = new DefaultListModel<>();
for (E item : items) {
model.add(model.getSize(), item);
}
return model;
}
@NotNull
public static <E> DefaultListModel<E> createDefaultListModel(@NotNull Iterable<? extends E> items) {
final DefaultListModel<E> model = new DefaultListModel<>();
for (E item : items) {
model.add(model.getSize(), item);
}
return model;
}
public JBList(@NotNull Collection<? extends E> items) {
this(JBList.<E>createDefaultListModel(items));
}
@Override
public void removeNotify() {
super.removeNotify();
if (!ScreenUtil.isStandardAddRemoveNotify(this)) return;
if (myBusyIcon != null) {
remove(myBusyIcon);
Disposer.dispose(myBusyIcon);
myBusyIcon = null;
}
}
@Override
public void doLayout() {
super.doLayout();
if (myBusyIcon != null) {
myBusyIcon.updateLocation(this);
}
}
@Override
public void paint(Graphics g) {
super.paint(g);
if (myBusyIcon != null) {
myBusyIcon.updateLocation(this);
}
}
public void setPaintBusy(boolean paintBusy) {
if (myBusy == paintBusy) return;
myBusy = paintBusy;
updateBusy();
}
private void updateBusy() {
if (myBusy) {
if (myBusyIcon == null) {
myBusyIcon = new AsyncProcessIcon(toString()).setUseMask(false);
myBusyIcon.setOpaque(false);
myBusyIcon.setPaintPassiveIcon(false);
add(myBusyIcon);
}
}
if (myBusyIcon != null) {
if (myBusy) {
myBusyIcon.resume();
}
else {
myBusyIcon.suspend();
//noinspection SSBasedInspection
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (myBusyIcon != null) {
repaint();
}
}
});
}
if (myBusyIcon != null) {
myBusyIcon.updateLocation(this);
}
}
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
myEmptyText.paint(this, g);
}
@Override
public Dimension getPreferredSize() {
if (getModel().getSize() == 0 && !StringUtil.isEmpty(getEmptyText().getText())) {
Dimension s = getEmptyText().getPreferredSize();
JBInsets.addTo(s, getInsets());
return s;
}
else {
return super.getPreferredSize();
}
}
private void init() {
setSelectionBackground(UIUtil.getListSelectionBackground());
setSelectionForeground(UIUtil.getListSelectionForeground());
myEmptyText = new StatusText(this) {
@Override
protected boolean isStatusVisible() {
return JBList.this.isEmpty();
}
};
myExpandableItemsHandler = createExpandableItemsHandler();
setCellRenderer(new DefaultListCellRenderer());
}
public boolean isEmpty() {
return getItemsCount() == 0;
}
public int getItemsCount() {
ListModel model = getModel();
return model == null ? 0 : model.getSize();
}
@NotNull
@Override
public StatusText getEmptyText() {
return myEmptyText;
}
public void setEmptyText(@NotNull String text) {
myEmptyText.setText(text);
}
@Override
@NotNull
public ExpandableItemsHandler<Integer> getExpandableItemsHandler() {
return myExpandableItemsHandler;
}
@NotNull
protected ExpandableItemsHandler<Integer> createExpandableItemsHandler() {
return ExpandableItemsHandlerFactory.install(this);
}
@Override
public void setExpandableItemsEnabled(boolean enabled) {
myExpandableItemsHandler.setEnabled(enabled);
}
@Override
public void setCellRenderer(ListCellRenderer<? super E> cellRenderer) {
// myExpandableItemsHandler may not yeb be initialized
//noinspection ConstantConditions
if (myExpandableItemsHandler == null) {
super.setCellRenderer(cellRenderer);
return;
}
super.setCellRenderer(new ExpandedItemListCellRendererWrapper<>(cellRenderer, myExpandableItemsHandler));
}
public <T> void installCellRenderer(@NotNull final NotNullFunction<T, JComponent> fun) {
setCellRenderer(new DefaultListCellRenderer() {
@NotNull
@Override
public Component getListCellRendererComponent(@NotNull JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
@SuppressWarnings({"unchecked"})
final JComponent comp = fun.fun((T)value);
comp.setOpaque(true);
if (isSelected) {
comp.setBackground(list.getSelectionBackground());
comp.setForeground(list.getSelectionForeground());
}
else {
comp.setBackground(list.getBackground());
comp.setForeground(list.getForeground());
}
for (JLabel label : UIUtil.findComponentsOfType(comp, JLabel.class)) {
label.setForeground(UIUtil.getListForeground(isSelected));
}
return comp;
}
});
}
public void setDataProvider(@NotNull DataProvider provider) {
DataManager.registerDataProvider(this, provider);
}
public void disableEmptyText() {
getEmptyText().setText("");
}
public static class StripedListCellRenderer extends DefaultListCellRenderer {
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (!isSelected && index % 2 == 0) {
setBackground(UIUtil.getDecoratedRowColor());
}
return this;
}
}
}