mirror of
https://github.com/TermoraDev/termora.git
synced 2026-01-16 02:12:58 +08:00
257 lines
9.0 KiB
Kotlin
257 lines
9.0 KiB
Kotlin
package app.termora
|
|
|
|
|
|
import app.termora.actions.DataProvider
|
|
import app.termora.actions.DataProviderSupport
|
|
import app.termora.actions.DataProviders
|
|
import app.termora.sftp.SFTPTab
|
|
import app.termora.terminal.DataKey
|
|
import com.formdev.flatlaf.FlatClientProperties
|
|
import com.formdev.flatlaf.util.SystemInfo
|
|
import com.jetbrains.JBR
|
|
import java.awt.BorderLayout
|
|
import java.awt.Dimension
|
|
import java.awt.Insets
|
|
import java.awt.event.MouseAdapter
|
|
import java.awt.event.MouseEvent
|
|
import java.awt.event.MouseListener
|
|
import java.awt.event.MouseMotionListener
|
|
import java.util.*
|
|
import javax.imageio.ImageIO
|
|
import javax.swing.*
|
|
import javax.swing.SwingUtilities.isEventDispatchThread
|
|
|
|
fun assertEventDispatchThread() {
|
|
if (!isEventDispatchThread()) throw WrongThreadException("AWT EventQueue")
|
|
}
|
|
|
|
|
|
class TermoraFrame : JFrame(), DataProvider {
|
|
|
|
|
|
private val id = UUID.randomUUID().toString()
|
|
private val windowScope = ApplicationScope.forWindowScope(this)
|
|
private val tabbedPane = MyTabbedPane()
|
|
private val toolbar = TermoraToolBar(windowScope, this, tabbedPane)
|
|
private val terminalTabbed = TerminalTabbed(windowScope, toolbar, tabbedPane)
|
|
private val dataProviderSupport = DataProviderSupport()
|
|
private val welcomePanel = WelcomePanel(windowScope)
|
|
private val sftp get() = Database.getDatabase().sftp
|
|
private val myUI = MyFlatRootPaneUI()
|
|
|
|
|
|
init {
|
|
initView()
|
|
initEvents()
|
|
}
|
|
|
|
private fun initEvents() {
|
|
if (SystemInfo.isLinux) {
|
|
val mouseAdapter = object : MouseAdapter() {
|
|
override fun mouseClicked(e: MouseEvent) {
|
|
getMouseHandler()?.mouseClicked(e)
|
|
}
|
|
|
|
override fun mousePressed(e: MouseEvent) {
|
|
getMouseHandler()?.mousePressed(e)
|
|
}
|
|
|
|
override fun mouseDragged(e: MouseEvent) {
|
|
val mouseLayer = getMouseLayer() ?: return
|
|
getMouseMotionListener()?.mouseDragged(
|
|
MouseEvent(
|
|
mouseLayer,
|
|
e.id,
|
|
e.`when`,
|
|
e.modifiersEx,
|
|
e.x,
|
|
e.y,
|
|
e.clickCount,
|
|
e.isPopupTrigger,
|
|
e.button
|
|
)
|
|
)
|
|
}
|
|
|
|
private fun getMouseHandler(): MouseListener? {
|
|
return getHandler() as? MouseListener
|
|
}
|
|
|
|
private fun getMouseMotionListener(): MouseMotionListener? {
|
|
return getHandler() as? MouseMotionListener
|
|
}
|
|
|
|
private fun getMouseLayer(): JComponent? {
|
|
val titlePane = myUI.getTitlePane() ?: return null
|
|
val handlerField = titlePane.javaClass.getDeclaredField("mouseLayer") ?: return null
|
|
handlerField.isAccessible = true
|
|
return handlerField.get(titlePane) as? JComponent
|
|
}
|
|
|
|
private fun getHandler(): Any? {
|
|
val titlePane = myUI.getTitlePane() ?: return null
|
|
val handlerField = titlePane.javaClass.getDeclaredField("handler") ?: return null
|
|
handlerField.isAccessible = true
|
|
return handlerField.get(titlePane)
|
|
}
|
|
}
|
|
toolbar.getJToolBar().addMouseListener(mouseAdapter)
|
|
toolbar.getJToolBar().addMouseMotionListener(mouseAdapter)
|
|
}
|
|
|
|
/// force hit
|
|
if (SystemInfo.isMacOS) {
|
|
if (JBR.isWindowDecorationsSupported()) {
|
|
val height = UIManager.getInt("TabbedPane.tabHeight") + tabbedPane.tabAreaInsets.top
|
|
val customTitleBar = JBR.getWindowDecorations().createCustomTitleBar()
|
|
customTitleBar.height = height.toFloat()
|
|
|
|
val mouseAdapter = object : MouseAdapter() {
|
|
|
|
private fun hit(e: MouseEvent) {
|
|
if (e.source == tabbedPane) {
|
|
val index = tabbedPane.indexAtLocation(e.x, e.y)
|
|
if (index >= 0) {
|
|
return
|
|
}
|
|
}
|
|
customTitleBar.forceHitTest(false)
|
|
}
|
|
|
|
override fun mouseClicked(e: MouseEvent) {
|
|
hit(e)
|
|
}
|
|
|
|
override fun mousePressed(e: MouseEvent) {
|
|
hit(e)
|
|
}
|
|
|
|
override fun mouseReleased(e: MouseEvent) {
|
|
hit(e)
|
|
}
|
|
|
|
override fun mouseEntered(e: MouseEvent) {
|
|
hit(e)
|
|
}
|
|
|
|
override fun mouseDragged(e: MouseEvent) {
|
|
hit(e)
|
|
}
|
|
|
|
override fun mouseMoved(e: MouseEvent) {
|
|
hit(e)
|
|
}
|
|
}
|
|
|
|
terminalTabbed.addMouseListener(mouseAdapter)
|
|
terminalTabbed.addMouseMotionListener(mouseAdapter)
|
|
|
|
tabbedPane.addMouseListener(mouseAdapter)
|
|
tabbedPane.addMouseMotionListener(mouseAdapter)
|
|
|
|
toolbar.getJToolBar().addMouseListener(mouseAdapter)
|
|
toolbar.getJToolBar().addMouseMotionListener(mouseAdapter)
|
|
|
|
JBR.getWindowDecorations().setCustomTitleBar(this, customTitleBar)
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
private fun initView() {
|
|
|
|
// macOS 要避开左边的控制栏
|
|
if (SystemInfo.isMacOS) {
|
|
tabbedPane.tabAreaInsets = Insets(0, 76, 0, 0)
|
|
} else if (SystemInfo.isWindows) {
|
|
// Windows 10 会有1像素误差
|
|
tabbedPane.tabAreaInsets = Insets(if (SystemInfo.isWindows_11_orLater) 1 else 2, 2, 0, 0)
|
|
} else if (SystemInfo.isLinux) {
|
|
rootPane.setUI(myUI)
|
|
tabbedPane.tabAreaInsets = Insets(1, 2, 0, 0)
|
|
}
|
|
|
|
val height = UIManager.getInt("TabbedPane.tabHeight") + tabbedPane.tabAreaInsets.top
|
|
|
|
if (SystemInfo.isWindows || SystemInfo.isLinux) {
|
|
rootPane.putClientProperty(FlatClientProperties.FULL_WINDOW_CONTENT, true)
|
|
rootPane.putClientProperty(FlatClientProperties.TITLE_BAR_SHOW_ICON, false)
|
|
rootPane.putClientProperty(FlatClientProperties.TITLE_BAR_SHOW_TITLE, false)
|
|
rootPane.putClientProperty(FlatClientProperties.TITLE_BAR_HEIGHT, height)
|
|
} else if (SystemInfo.isMacOS) {
|
|
rootPane.putClientProperty("apple.awt.windowTitleVisible", false)
|
|
rootPane.putClientProperty("apple.awt.fullWindowContent", true)
|
|
rootPane.putClientProperty("apple.awt.transparentTitleBar", true)
|
|
rootPane.putClientProperty(
|
|
FlatClientProperties.MACOS_WINDOW_BUTTONS_SPACING,
|
|
FlatClientProperties.MACOS_WINDOW_BUTTONS_SPACING_MEDIUM
|
|
)
|
|
}
|
|
|
|
if (SystemInfo.isWindows || SystemInfo.isLinux) {
|
|
val sizes = listOf(16, 20, 24, 28, 32, 48, 64)
|
|
val loader = TermoraFrame::class.java.classLoader
|
|
val images = sizes.mapNotNull { e ->
|
|
loader.getResourceAsStream("icons/termora_${e}x${e}.png")?.use { ImageIO.read(it) }
|
|
}
|
|
iconImages = images
|
|
}
|
|
|
|
minimumSize = Dimension(640, 400)
|
|
terminalTabbed.addTerminalTab(welcomePanel)
|
|
|
|
// 下一次事件循环检测是否固定 SFTP
|
|
if (sftp.pinTab) {
|
|
SwingUtilities.invokeLater {
|
|
terminalTabbed.addTerminalTab(SFTPTab(), false)
|
|
}
|
|
}
|
|
|
|
|
|
Disposer.register(windowScope, terminalTabbed)
|
|
add(terminalTabbed, BorderLayout.CENTER)
|
|
|
|
dataProviderSupport.addData(DataProviders.TabbedPane, tabbedPane)
|
|
dataProviderSupport.addData(DataProviders.TermoraFrame, this)
|
|
dataProviderSupport.addData(DataProviders.WindowScope, windowScope)
|
|
}
|
|
|
|
override fun <T : Any> getData(dataKey: DataKey<T>): T? {
|
|
return dataProviderSupport.getData(dataKey)
|
|
?: terminalTabbed.getData(dataKey)
|
|
?: welcomePanel.getData(dataKey)
|
|
}
|
|
|
|
|
|
override fun equals(other: Any?): Boolean {
|
|
if (this === other) return true
|
|
if (javaClass != other?.javaClass) return false
|
|
|
|
other as TermoraFrame
|
|
|
|
return id == other.id
|
|
}
|
|
|
|
override fun hashCode(): Int {
|
|
return id.hashCode()
|
|
}
|
|
|
|
override fun addNotify() {
|
|
super.addNotify()
|
|
|
|
val dialog = object : DialogWrapper(this@TermoraFrame) {
|
|
init {
|
|
init()
|
|
controlsVisible = false
|
|
}
|
|
|
|
override fun createCenterPanel(): JComponent {
|
|
return JPanel()
|
|
}
|
|
}
|
|
dialog.title = "Hello"
|
|
dialog.size = Dimension(800, 600)
|
|
dialog.setLocationRelativeTo(this)
|
|
// dialog.isVisible = true
|
|
}
|
|
} |