diff --git a/plugins/android/src/org/jetbrains/android/uipreview/AndroidLayoutPreviewPanel.java b/plugins/android/src/org/jetbrains/android/uipreview/AndroidLayoutPreviewPanel.java index aec79515f7e1..131cdd944ffb 100644 --- a/plugins/android/src/org/jetbrains/android/uipreview/AndroidLayoutPreviewPanel.java +++ b/plugins/android/src/org/jetbrains/android/uipreview/AndroidLayoutPreviewPanel.java @@ -1,9 +1,12 @@ package org.jetbrains.android.uipreview; + import com.intellij.openapi.Disposable; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.VerticalFlowLayout; + import com.intellij.openapi.util.Disposer; import com.intellij.ui.HyperlinkLabel; import com.intellij.ui.components.JBLabel; + import com.intellij.util.ui.AsyncProcessIcon; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -15,7 +18,7 @@ /** * @author Eugene.Kudelevsky */ -public class AndroidLayoutPreviewPanel extends JPanel { +public class AndroidLayoutPreviewPanel extends JPanel implements Disposable { private static final double EPS = 0.0000001; private static final double MAX_ZOOM_FACTOR = 2.0; private static final double ZOOM_STEP = 1.25; @@ -23,7 +26,6 @@ public class AndroidLayoutPreviewPanel extends JPanel { private RenderingErrorMessage myErrorMessage; private String myWarnMessage; private BufferedImage myImage; - private JBLabel myProgressLabel; private final HyperlinkLabel myErrorLabel = new HyperlinkLabel("", Color.BLUE, getBackground(), Color.BLUE); @@ -46,6 +48,8 @@ public class AndroidLayoutPreviewPanel extends JPanel { } }; + private AsyncProcessIcon myProgressIcon; + public AndroidLayoutPreviewPanel() { super(new VerticalFlowLayout(VerticalFlowLayout.TOP, 0, 0, true, true)); setBackground(Color.WHITE); @@ -62,12 +66,18 @@ public class AndroidLayoutPreviewPanel extends JPanel { }); myErrorLabel.setOpaque(false); - myProgressLabel = new JBLabel("Rendering..."); - myProgressLabel.setIcon(Messages.getInformationIcon()); - myProgressLabel.setVisible(false); + final JPanel progressPanel = new JPanel(); + progressPanel.setLayout(new BoxLayout(progressPanel, BoxLayout.X_AXIS)); + myProgressIcon = new AsyncProcessIcon("Android layout rendering"); + Disposer.register(this, myProgressIcon); + progressPanel.add(Box.createHorizontalGlue()); + progressPanel.add(myProgressIcon); + progressPanel.add(new JBLabel(" ")); + progressPanel.setOpaque(false); + myProgressIcon.setVisible(false); + add(progressPanel); add(myErrorLabel); - add(myProgressLabel); add(new MyImagePanelWrapper()); } @@ -77,14 +87,13 @@ public class AndroidLayoutPreviewPanel extends JPanel { } public void showProgress() { - myProgressLabel.setVisible(true); - myErrorLabel.setVisible(false); - myImagePanel.setVisible(false); + myProgressIcon.setVisible(true); + myProgressIcon.resume(); } - @Nullable - public BufferedImage getImage() { - return myImage; + public void hideProgress() { + myProgressIcon.suspend(); + myProgressIcon.setVisible(false); } private void doRevalidate() { @@ -102,7 +111,6 @@ public class AndroidLayoutPreviewPanel extends JPanel { } public void update() { - myProgressLabel.setVisible(false); myImagePanel.setVisible(true); if (myErrorMessage != null) { myErrorLabel.setHyperlinkText(myErrorMessage.myBeforeLinkText, @@ -218,6 +226,10 @@ public class AndroidLayoutPreviewPanel extends JPanel { return myZoomToFit; } + @Override + public void dispose() { + } + private class MyImagePanelWrapper extends JLayeredPane { public MyImagePanelWrapper() { add(myImagePanel); diff --git a/plugins/android/src/org/jetbrains/android/uipreview/AndroidLayoutPreviewToolWindowForm.java b/plugins/android/src/org/jetbrains/android/uipreview/AndroidLayoutPreviewToolWindowForm.java index 887d002f93fb..49cf5ce55357 100644 --- a/plugins/android/src/org/jetbrains/android/uipreview/AndroidLayoutPreviewToolWindowForm.java +++ b/plugins/android/src/org/jetbrains/android/uipreview/AndroidLayoutPreviewToolWindowForm.java @@ -5,10 +5,10 @@ import com.android.ide.common.resources.ResourceResolver; import com.android.ide.common.resources.configuration.LanguageQualifier; import com.android.ide.common.resources.configuration.RegionQualifier; import com.android.ide.common.resources.configuration.ScreenSizeQualifier; -import com.android.resources.UiMode; import com.android.resources.NightMode; import com.android.resources.ResourceType; import com.android.resources.ScreenSize; +import com.android.resources.UiMode; import com.android.sdklib.IAndroidTarget; import com.android.sdklib.SdkConstants; import com.intellij.ide.ui.ListCellRendererWrapper; @@ -23,6 +23,7 @@ import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.ui.ComboBox; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; @@ -97,6 +98,8 @@ class AndroidLayoutPreviewToolWindowForm implements Disposable { private final AndroidLayoutPreviewToolWindowSettings mySettings; public AndroidLayoutPreviewToolWindowForm(final Project project, AndroidLayoutPreviewToolWindowManager toolWindowManager) { + Disposer.register(this, myPreviewPanel); + myToolWindowManager = toolWindowManager; mySettings = AndroidLayoutPreviewToolWindowSettings.getInstance(project); diff --git a/plugins/android/src/org/jetbrains/android/uipreview/AndroidLayoutPreviewToolWindowManager.java b/plugins/android/src/org/jetbrains/android/uipreview/AndroidLayoutPreviewToolWindowManager.java index 24aa068a2779..2b8b7cb3dbba 100644 --- a/plugins/android/src/org/jetbrains/android/uipreview/AndroidLayoutPreviewToolWindowManager.java +++ b/plugins/android/src/org/jetbrains/android/uipreview/AndroidLayoutPreviewToolWindowManager.java @@ -5,7 +5,6 @@ import com.android.sdklib.IAndroidTarget; import com.intellij.ProjectTopics; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.components.ProjectComponent; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; @@ -13,6 +12,8 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.fileEditor.*; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtil; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.util.ProgressIndicatorBase; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.roots.ModuleRootEvent; @@ -35,6 +36,7 @@ import com.intellij.ui.content.Content; import com.intellij.ui.content.ContentManager; import com.intellij.util.containers.HashMap; import com.intellij.util.messages.MessageBusConnection; +import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.update.MergingUpdateQueue; import com.intellij.util.ui.update.Update; import org.jetbrains.android.dom.layout.LayoutDomFileDescription; @@ -53,6 +55,8 @@ import org.jetbrains.annotations.Nullable; import javax.imageio.ImageIO; import javax.swing.*; import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; @@ -242,15 +246,12 @@ public class AndroidLayoutPreviewToolWindowManager implements ProjectComponent { myRenderingQueue.queue(new Update("render") { @Override public void run() { - if (showProgress || myToolWindowForm.getPreviewPanel().getImage() == null) { - ApplicationManager.getApplication().invokeAndWait(new Runnable() { - @Override - public void run() { - myToolWindowForm.getPreviewPanel().showProgress(); - } - }, ModalityState.defaultModalityState()); - } - doRender(facet, layoutXmlText); + ProgressManager.getInstance().runProcess(new Runnable() { + @Override + public void run() { + doRender(facet, layoutXmlText); + } + }, new MyProgressIndicator()); } @Override @@ -355,7 +356,7 @@ public class AndroidLayoutPreviewToolWindowManager implements ProjectComponent { } }); } - + private void showStackStace(@NotNull Throwable t) { final String stackTrace = getStackTrace(t); final DialogWrapper wrapper = new DialogWrapper(myProject, false) { @@ -372,11 +373,11 @@ public class AndroidLayoutPreviewToolWindowManager implements ProjectComponent { panel.add(ScrollPaneFactory.createScrollPane(textArea)); return panel; } - }; + }; wrapper.setTitle("Stack trace"); wrapper.show(); } - + @NotNull private static String getStackTrace(@NotNull Throwable t) { final StringWriter stringWriter = new StringWriter(); @@ -517,4 +518,43 @@ public class AndroidLayoutPreviewToolWindowManager implements ProjectComponent { processFileEditorChange(layoutXmlEditor); } } + + private class MyProgressIndicator extends ProgressIndicatorBase { + private final Object myLock = new Object(); + + @Override + public void start() { + super.start(); + UIUtil.invokeLaterIfNeeded(new Runnable() { + @Override + public void run() { + final Timer timer = UIUtil.createNamedTimer("Android rendering progress timer", 1000, new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + synchronized (myLock) { + if (isRunning()) { + myToolWindowForm.getPreviewPanel().showProgress(); + } + } + } + }); + timer.setRepeats(false); + timer.start(); + } + }); + } + + @Override + public void stop() { + synchronized (myLock) { + super.stop(); + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + myToolWindowForm.getPreviewPanel().hideProgress(); + } + }); + } + } + } }