/*
* Copyright 2013-2016 consulo.io
*
* 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 consulo.ide;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.util.Iconable;
import com.intellij.openapi.util.NotNullLazyValue;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.SmartPointerManager;
import com.intellij.psi.SmartPsiElementPointer;
import com.intellij.ui.IconDeferrer;
import com.intellij.ui.RowIcon;
import com.intellij.util.NullableFunction;
import com.intellij.util.ui.EmptyIcon;
import consulo.annotations.RequiredReadAction;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
/**
* @author VISTALL
* @since 0:25/19.07.13
*/
public class IconDescriptorUpdaters {
private static final NotNullLazyValue<Icon> ourVisibilityIconPlaceholder = NotNullLazyValue.createValue(() -> EmptyIcon.create(AllIcons.Nodes.C_public));
private static final NullableFunction<ElementIconRequest, Icon> ourIconCompute = request -> {
final PsiElement element = request.myPointer.getElement();
if (element == null || !element.isValid() || element.getProject().isDisposed()) return null;
Icon icon = getIconWithoutCache(element, request.myFlags);
Iconable.LastComputedIcon.put(element, icon, request.myFlags);
return icon;
};
private static class ElementIconRequest {
private final SmartPsiElementPointer<?> myPointer;
@Iconable.IconFlags
private final int myFlags;
public ElementIconRequest(PsiElement element, @Iconable.IconFlags int flags) {
myPointer = SmartPointerManager.getInstance(element.getProject()).createSmartPsiElementPointer(element);
myFlags = flags;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ElementIconRequest)) return false;
ElementIconRequest request = (ElementIconRequest)o;
if (myFlags != request.myFlags) return false;
if (!myPointer.equals(request.myPointer)) return false;
return true;
}
@Override
public String toString() {
return myPointer.toString() + "/" + myFlags;
}
@Override
public int hashCode() {
int result = myPointer.hashCode();
result = 31 * result + myFlags;
return result;
}
}
@NotNull
@RequiredReadAction
public static Icon getIcon(@NotNull final PsiElement element, @Iconable.IconFlags final int flags) {
if (!element.isValid()) return AllIcons.Nodes.NodePlaceholder;
Icon baseIcon = Iconable.LastComputedIcon.get(element, flags);
if (baseIcon == null) {
baseIcon = computeBaseIcon(element, flags);
}
return IconDeferrer.getInstance().defer(baseIcon, new ElementIconRequest(element, flags), ourIconCompute);
}
@NotNull
private static Icon computeBaseIcon(@NotNull PsiElement element, int flags) {
Icon icon = computeBaseIcon(element);
if ((flags & Iconable.ICON_FLAG_VISIBILITY) > 0) {
return new RowIcon(icon, ourVisibilityIconPlaceholder.getValue());
}
return icon;
}
@NotNull
private static Icon computeBaseIcon(@NotNull PsiElement element) {
PsiFile containingFile = element.getContainingFile();
if (containingFile != null) {
VirtualFile virtualFile = containingFile.getVirtualFile();
if (virtualFile != null) {
Icon icon = virtualFile.getFileType().getIcon();
if (icon != null) {
return icon;
}
}
}
return AllIcons.Nodes.NodePlaceholder;
}
@NotNull
@RequiredReadAction
public static Icon getIconWithoutCache(@NotNull PsiElement element, int flags) {
IconDescriptor iconDescriptor = new IconDescriptor(null);
IconDescriptorUpdater.EP_NAME.composite().updateIcon(iconDescriptor, element, flags);
return iconDescriptor.toIcon();
}
@RequiredReadAction
public static void processExistingDescriptor(@NotNull IconDescriptor iconDescriptor, @NotNull PsiElement element, int flags) {
IconDescriptorUpdater.EP_NAME.composite().updateIcon(iconDescriptor, element, flags);
}
}