mirror of
https://github.com/jlengrand/compose-multiplatform.git
synced 2026-03-10 08:11:20 +00:00
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020-2021 JetBrains s.r.o. and respective authors and developers.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.compose.desktop.ui.tooling.preview.rpc
|
||||
|
||||
interface PreviewErrorReporter {
|
||||
fun report(e: Throwable, details: String? = null)
|
||||
fun report(e: String, details: String? = null)
|
||||
}
|
||||
|
||||
object StderrPreviewErrorReporter : PreviewErrorReporter {
|
||||
override fun report(e: Throwable, details: String?) {
|
||||
report(e.stackTraceString)
|
||||
}
|
||||
|
||||
override fun report(e: String, details: String?) {
|
||||
System.err.println(e)
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ interface PreviewListener {
|
||||
fun onFinishedBuild(success: Boolean)
|
||||
fun onNewRenderRequest(previewRequest: FrameRequest)
|
||||
fun onRenderedFrame(frame: RenderedFrame)
|
||||
fun onIncompatibleProtocolVersions(versionServer: Int, versionClient: Int)
|
||||
fun onError(error: String)
|
||||
}
|
||||
|
||||
open class PreviewListenerBase : PreviewListener {
|
||||
@@ -20,7 +20,7 @@ open class PreviewListenerBase : PreviewListener {
|
||||
override fun onNewRenderRequest(previewRequest: FrameRequest) {}
|
||||
override fun onRenderedFrame(frame: RenderedFrame) {}
|
||||
|
||||
override fun onIncompatibleProtocolVersions(versionServer: Int, versionClient: Int) {}
|
||||
override fun onError(error: String) {}
|
||||
}
|
||||
|
||||
class CompositePreviewListener : PreviewListener {
|
||||
@@ -42,8 +42,8 @@ class CompositePreviewListener : PreviewListener {
|
||||
forEachListener { it.onRenderedFrame(frame) }
|
||||
}
|
||||
|
||||
override fun onIncompatibleProtocolVersions(versionServer: Int, versionClient: Int) {
|
||||
forEachListener { it.onIncompatibleProtocolVersions(versionServer, versionClient) }
|
||||
override fun onError(error: String) {
|
||||
forEachListener { it.onError(error) }
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
|
||||
@@ -50,8 +50,7 @@ private data class RunningPreview(
|
||||
}
|
||||
|
||||
class PreviewManagerImpl(
|
||||
private val previewListener: PreviewListener = PreviewListenerBase(),
|
||||
private val errorReporter: PreviewErrorReporter = StderrPreviewErrorReporter
|
||||
private val previewListener: PreviewListener
|
||||
) : PreviewManager {
|
||||
// todo: add quiet mode
|
||||
private val log = PrintStreamLogger("SERVER")
|
||||
@@ -125,7 +124,7 @@ class PreviewManagerImpl(
|
||||
appendLine(exception)
|
||||
}
|
||||
}
|
||||
errorReporter.report(PreviewException(errorMessage), details = processLogLines.joinToString("\n"))
|
||||
onError(errorMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -160,10 +159,10 @@ class PreviewManagerImpl(
|
||||
previewListener.onRenderedFrame(renderedFrame)
|
||||
},
|
||||
onError = { error ->
|
||||
errorReporter.report(PreviewException(error))
|
||||
previewHostConfig.set(null)
|
||||
previewClasspath.set(null)
|
||||
inProcessRequest.set(null)
|
||||
onError(error)
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -292,9 +291,18 @@ class PreviewManagerImpl(
|
||||
}
|
||||
}.also {
|
||||
it.uncaughtExceptionHandler = Thread.UncaughtExceptionHandler { thread, e ->
|
||||
errorReporter.report(e)
|
||||
onError(e)
|
||||
}
|
||||
threads.add(it)
|
||||
it.start()
|
||||
}
|
||||
|
||||
private fun onError(e: Throwable) {
|
||||
onError(e.stackTraceString)
|
||||
}
|
||||
|
||||
private fun onError(error: String) {
|
||||
log.error { error }
|
||||
previewListener.onError(error)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,9 @@ internal fun RemoteConnection.receiveAttach(
|
||||
if (type == Command.Type.ATTACH) {
|
||||
val version = args.firstOrNull()?.toIntOrNull() ?: 0
|
||||
if (PROTOCOL_VERSION != version) {
|
||||
listener?.onIncompatibleProtocolVersions(PROTOCOL_VERSION, version)
|
||||
listener?.onError(
|
||||
"Compose Multiplatform Gradle plugin version is not compatible with Intellij plugin version"
|
||||
)
|
||||
}
|
||||
fn()
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020-2021 JetBrains s.r.o. and respective authors and developers.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.compose.desktop.ide.preview
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import org.jetbrains.compose.desktop.ui.tooling.preview.rpc.PreviewErrorReporter
|
||||
|
||||
internal class IdePreviewErrorReporter(
|
||||
private val logger: Logger,
|
||||
private val previewStateService: PreviewStateService
|
||||
) : PreviewErrorReporter {
|
||||
override fun report(e: Throwable, details: String?) {
|
||||
report(e.stackTraceToString(), details)
|
||||
}
|
||||
|
||||
override fun report(e: String, details: String?) {
|
||||
if (details != null) {
|
||||
logger.error(e, details)
|
||||
} else {
|
||||
logger.error(e)
|
||||
}
|
||||
previewStateService.clearPreviewOnError()
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020-2021 JetBrains s.r.o. and respective authors and developers.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.compose.desktop.ide.preview
|
||||
|
||||
import java.awt.Color
|
||||
import java.awt.Dimension
|
||||
import java.awt.Graphics
|
||||
import java.awt.image.BufferedImage
|
||||
import javax.swing.JPanel
|
||||
|
||||
internal class PreviewPanel : JPanel() {
|
||||
private var image: BufferedImage? = null
|
||||
private var imageDimension: Dimension? = null
|
||||
|
||||
override fun paintComponent(g: Graphics) {
|
||||
super.paintComponent(g)
|
||||
|
||||
synchronized(this) {
|
||||
image?.let { image ->
|
||||
val w = imageDimension!!.width
|
||||
val h = imageDimension!!.height
|
||||
g.color = Color.WHITE
|
||||
g.fillRect(0, 0, w, h)
|
||||
g.drawImage(image, 0, 0, w, h, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun previewImage(image: BufferedImage?, imageDimension: Dimension?) {
|
||||
synchronized(this) {
|
||||
this.image = image
|
||||
this.imageDimension = imageDimension
|
||||
}
|
||||
|
||||
repaint()
|
||||
}
|
||||
|
||||
override fun getPreferredSize(): Dimension? =
|
||||
imageDimension ?: super.getPreferredSize()
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.wm.ToolWindow
|
||||
import com.intellij.openapi.wm.ToolWindowFactory
|
||||
import com.intellij.ui.components.JBLoadingPanel
|
||||
import org.jetbrains.compose.desktop.ide.preview.ui.PreviewPanel
|
||||
import java.awt.BorderLayout
|
||||
|
||||
class PreviewToolWindow : ToolWindowFactory, DumbAware {
|
||||
@@ -24,7 +25,7 @@ class PreviewToolWindow : ToolWindowFactory, DumbAware {
|
||||
|
||||
override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) {
|
||||
toolWindow.contentManager.let { content ->
|
||||
val panel = PreviewPanel()
|
||||
val panel = PreviewPanel(project)
|
||||
val loadingPanel = JBLoadingPanel(BorderLayout(), project)
|
||||
loadingPanel.add(panel, BorderLayout.CENTER)
|
||||
content.addContent(content.factory.createContent(loadingPanel, null, false))
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2020-2022 JetBrains s.r.o. and respective authors and developers.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.compose.desktop.ide.preview.ui
|
||||
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.ui.SimpleTextAttributes
|
||||
import com.intellij.ui.components.JBPanel
|
||||
import com.intellij.util.ui.StatusText
|
||||
import java.awt.Color
|
||||
import java.awt.Dimension
|
||||
import java.awt.Graphics
|
||||
import java.awt.image.BufferedImage
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
import javax.swing.SwingUtilities
|
||||
|
||||
internal class PreviewPanel(private val myProject: Project) : JBPanel<PreviewPanel>() {
|
||||
sealed class PreviewPanelState {
|
||||
data class Image(val image: BufferedImage, val dimension: Dimension) : PreviewPanelState()
|
||||
class Error(val error: String) : PreviewPanelState()
|
||||
}
|
||||
private val myState = AtomicReference<PreviewPanelState>()
|
||||
private val myStatusText = object : StatusText(this) {
|
||||
override fun isStatusVisible(): Boolean {
|
||||
return myState.get() is PreviewPanelState.Error
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
SwingUtilities.invokeLater {
|
||||
myStatusText.initStatusText()
|
||||
}
|
||||
}
|
||||
|
||||
fun StatusText.initStatusText() {
|
||||
clear()
|
||||
appendLine(
|
||||
AllIcons.General.Error,
|
||||
"Preview rendering encountered an error",
|
||||
SimpleTextAttributes.REGULAR_ATTRIBUTES,
|
||||
null
|
||||
)
|
||||
appendLine(
|
||||
"Show details",
|
||||
SimpleTextAttributes.LINK_ATTRIBUTES
|
||||
) {
|
||||
val errorText = (myState.get() as? PreviewPanelState.Error)?.error
|
||||
showTextDialog("Preview Error Details", errorText.orEmpty(), myProject)
|
||||
}
|
||||
}
|
||||
|
||||
override fun paintComponent(g: Graphics) {
|
||||
super.paintComponent(g)
|
||||
|
||||
when (val state = myState.get()) {
|
||||
is PreviewPanelState.Image -> {
|
||||
val (image, dimension) = state
|
||||
val w = dimension.width
|
||||
val h = dimension.height
|
||||
g.color = Color.WHITE
|
||||
g.fillRect(0, 0, w, h)
|
||||
g.drawImage(image, 0, 0, w, h, null)
|
||||
}
|
||||
is PreviewPanelState.Error -> {
|
||||
myStatusText.paint(this, g)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun previewImage(image: BufferedImage, imageDimension: Dimension) {
|
||||
myState.set(PreviewPanelState.Image(image, imageDimension))
|
||||
SwingUtilities.invokeLater {
|
||||
repaint()
|
||||
}
|
||||
}
|
||||
|
||||
fun error(error: String) {
|
||||
myState.set(PreviewPanelState.Error(error))
|
||||
SwingUtilities.invokeLater {
|
||||
repaint()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getPreferredSize(): Dimension? =
|
||||
(myState.get() as? PreviewPanelState.Image)?.dimension ?: super.getPreferredSize()
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2020-2022 JetBrains s.r.o. and respective authors and developers.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.compose.desktop.ide.preview.ui
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.ui.DialogWrapper
|
||||
import com.intellij.ui.ScrollPaneFactory
|
||||
import java.awt.BorderLayout
|
||||
import javax.swing.JComponent
|
||||
import javax.swing.JPanel
|
||||
import javax.swing.JTextArea
|
||||
|
||||
fun showTextDialog(
|
||||
title: String,
|
||||
text: String,
|
||||
project: Project? = null
|
||||
) {
|
||||
val wrapper: DialogWrapper = object : DialogWrapper(project, false) {
|
||||
init {
|
||||
init()
|
||||
}
|
||||
|
||||
override fun createCenterPanel(): JComponent {
|
||||
val textArea = JTextArea(text).apply {
|
||||
isEditable = false
|
||||
rows = 40
|
||||
columns = 70
|
||||
}
|
||||
return JPanel(BorderLayout()).apply {
|
||||
add(ScrollPaneFactory.createScrollPane(textArea))
|
||||
}
|
||||
}
|
||||
}
|
||||
wrapper.title = title
|
||||
wrapper.show()
|
||||
}
|
||||
Reference in New Issue
Block a user