blob: 733a84b81c4b8b889b931d562da3cd47d24f7619 [file] [log] [blame]
/*
* Copyright 2000-2009 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.openapi.ui;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.util.Disposer;
import com.intellij.ui.components.JBLayeredPane;
import com.intellij.ui.components.panels.NonOpaquePanel;
import com.intellij.util.Alarm;
import com.intellij.util.ui.Animator;
import com.intellij.util.ui.AsyncProcessIcon;
import com.intellij.util.ui.UIUtil;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
public class LoadingDecorator {
JLayeredPane myPane = new MyLayeredPane();
LoadingLayer myLoadingLayer;
Animator myFadeOutAnimator;
int myDelay;
Alarm myStartAlarm;
boolean myStartRequest;
public LoadingDecorator(JComponent content, Disposable parent, int startDelayMs) {
myLoadingLayer = new LoadingLayer();
myDelay = startDelayMs;
myStartAlarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD, parent);
setLoadingText("Loading...");
myFadeOutAnimator = new Animator("Loading", 10, 500, false) {
public void paintNow(final int frame, final int totalFrames, final int cycle) {
myLoadingLayer.setAlpha(1f - ((float)frame) / ((float)totalFrames));
}
@Override
protected void paintCycleEnd() {
myLoadingLayer.setVisible(false);
myLoadingLayer.setAlpha(-1);
}
};
Disposer.register(parent, myFadeOutAnimator);
myPane.add(content, JLayeredPane.DEFAULT_LAYER, 0);
myPane.add(myLoadingLayer, JLayeredPane.DRAG_LAYER, 1);
Disposer.register(parent, myLoadingLayer.myProgress);
}
protected NonOpaquePanel customizeLoadingLayer(JPanel parent, JLabel text, AsyncProcessIcon icon) {
parent.setLayout(new GridBagLayout());
final Font font = text.getFont();
text.setFont(font.deriveFont(font.getStyle(), font.getSize() + 8));
//text.setForeground(Color.black);
final int gap = new JLabel().getIconTextGap();
final NonOpaquePanel result = new NonOpaquePanel(new FlowLayout(FlowLayout.CENTER, gap * 3, 0));
result.add(icon);
result.add(text);
parent.add(result);
return result;
}
public JComponent getComponent() {
return myPane;
}
public void startLoading(final boolean takeSnapshot) {
if (isLoading() || myStartRequest || myStartAlarm.isDisposed()) return;
myStartRequest = true;
if (myDelay > 0) {
myStartAlarm.addRequest(new Runnable() {
public void run() {
UIUtil.invokeLaterIfNeeded(new Runnable() {
public void run() {
if (!myStartRequest) return;
_startLoading(takeSnapshot);
}
});
}
}, myDelay);
} else {
_startLoading(takeSnapshot);
}
}
private void _startLoading(final boolean takeSnapshot) {
myLoadingLayer.setVisible(true, takeSnapshot);
}
public void stopLoading() {
myStartRequest = false;
myStartAlarm.cancelAllRequests();
if (!isLoading()) return;
myLoadingLayer.setVisible(false, false);
}
public String getLoadingText() {
return myLoadingLayer.myText.getText();
}
public void setLoadingText(final String loadingText) {
myLoadingLayer.myText.setText(loadingText);
}
public boolean isLoading() {
return myLoadingLayer.isVisible();
}
private class LoadingLayer extends JPanel {
private final JLabel myText = new JLabel("", SwingConstants.CENTER);
private BufferedImage mySnapshot;
private Color mySnapshotBg;
private final AsyncProcessIcon myProgress = new AsyncProcessIcon.Big("Loading");
private boolean myVisible;
private float myCurrentAlpha;
private final NonOpaquePanel myTextComponent;
private LoadingLayer() {
setOpaque(false);
setVisible(false);
myProgress.setOpaque(false);
myTextComponent = customizeLoadingLayer(this, myText, myProgress);
myProgress.suspend();
}
public void setVisible(final boolean visible, boolean takeSnapshot) {
if (myVisible == visible) return;
if (myVisible && !visible && myCurrentAlpha != -1) return;
myVisible = visible;
if (myVisible) {
setVisible(myVisible);
myCurrentAlpha = -1;
}
if (myVisible) {
if (takeSnapshot && getWidth() > 0 && getHeight() > 0) {
mySnapshot = UIUtil.createImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
final Graphics2D g = mySnapshot.createGraphics();
myPane.paint(g);
final Component opaque = UIUtil.findNearestOpaque(this);
mySnapshotBg = opaque != null ? opaque.getBackground() : UIUtil.getPanelBackground();
g.dispose();
}
myProgress.resume();
} else {
disposeSnapshot();
myProgress.suspend();
myFadeOutAnimator.reset();
myFadeOutAnimator.resume();
}
}
private void disposeSnapshot() {
if (mySnapshot != null) {
mySnapshot.flush();
mySnapshot = null;
}
}
@Override
protected void paintComponent(final Graphics g) {
if (mySnapshot != null) {
if (mySnapshot.getWidth() == getWidth() && mySnapshot.getHeight() == getHeight()) {
g.drawImage(mySnapshot, 0, 0, getWidth(), getHeight(), null);
g.setColor(new Color(200, 200, 200, 240));
g.fillRect(0, 0, getWidth(), getHeight());
return;
} else {
disposeSnapshot();
}
}
if (mySnapshotBg != null) {
g.setColor(mySnapshotBg);
g.fillRect(0, 0, getWidth(), getHeight());
}
}
public void setAlpha(final float alpha) {
myCurrentAlpha = alpha;
paintImmediately(myTextComponent.getBounds());
}
@Override
protected void paintChildren(final Graphics g) {
if (myCurrentAlpha != -1) {
((Graphics2D)g).setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, myCurrentAlpha));
}
super.paintChildren(g);
}
}
private static class MyLayeredPane extends JBLayeredPane {
@Override
public void doLayout() {
super.doLayout();
for (int i = 0; i < getComponentCount(); i++) {
final Component each = getComponent(i);
if (each instanceof Icon) {
each.setBounds(0, 0, each.getWidth(), each.getHeight());
} else {
each.setBounds(0, 0, getWidth(), getHeight());
}
}
}
}
}