mirror of
https://github.com/TermoraDev/termora.git
synced 2026-01-16 02:12:58 +08:00
feat: without jbr
This commit is contained in:
@@ -144,7 +144,7 @@ class ApplicationRunner {
|
||||
|
||||
private fun setupLaf() {
|
||||
|
||||
System.setProperty(FlatSystemProperties.USE_WINDOW_DECORATIONS, "${SystemInfo.isLinux}")
|
||||
System.setProperty(FlatSystemProperties.USE_WINDOW_DECORATIONS, "${SystemInfo.isLinux || SystemInfo.isWindows}")
|
||||
System.setProperty(FlatSystemProperties.USE_ROUNDED_POPUP_BORDER, "false")
|
||||
|
||||
if (SystemInfo.isLinux) {
|
||||
@@ -152,15 +152,6 @@ class ApplicationRunner {
|
||||
JDialog.setDefaultLookAndFeelDecorated(true)
|
||||
}
|
||||
|
||||
UIManager.put(
|
||||
"FileChooser.${if (SystemInfo.isWindows) "win32" else "other"}.newFolder",
|
||||
I18n.getString("termora.welcome.contextmenu.new.folder.name")
|
||||
)
|
||||
UIManager.put(
|
||||
"FileChooser.${if (SystemInfo.isWindows) "win32" else "other"}.newFolder.subsequent",
|
||||
"${I18n.getString("termora.welcome.contextmenu.new.folder.name")}.{0}"
|
||||
)
|
||||
|
||||
val themeManager = ThemeManager.getInstance()
|
||||
val appearance = Database.getDatabase().appearance
|
||||
var theme = appearance.theme
|
||||
@@ -176,8 +167,8 @@ class ApplicationRunner {
|
||||
themeManager.change(theme, true)
|
||||
|
||||
|
||||
if (Application.isUnknownVersion())
|
||||
FlatInspector.install("ctrl shift alt X")
|
||||
// if (Application.isUnknownVersion())
|
||||
FlatInspector.install("ctrl X")
|
||||
|
||||
UIManager.put(FlatClientProperties.FULL_WINDOW_CONTENT, true)
|
||||
UIManager.put(FlatClientProperties.USE_WINDOW_DECORATIONS, false)
|
||||
|
||||
@@ -2,8 +2,8 @@ package app.termora
|
||||
|
||||
import app.termora.actions.AnAction
|
||||
import app.termora.actions.AnActionEvent
|
||||
import app.termora.native.osx.NativeMacLibrary
|
||||
import com.formdev.flatlaf.FlatClientProperties
|
||||
import com.formdev.flatlaf.FlatLaf
|
||||
import com.formdev.flatlaf.util.SystemInfo
|
||||
import com.jetbrains.JBR
|
||||
import java.awt.*
|
||||
@@ -12,29 +12,60 @@ import java.awt.event.WindowAdapter
|
||||
import java.awt.event.WindowEvent
|
||||
import javax.swing.*
|
||||
|
||||
|
||||
abstract class DialogWrapper(owner: Window?) : JDialog(owner) {
|
||||
private val rootPanel = JPanel(BorderLayout())
|
||||
private val titleLabel = JLabel()
|
||||
private val titleBar by lazy { LogicCustomTitleBar.createCustomTitleBar(this) }
|
||||
val disposable = Disposer.newDisposable()
|
||||
private val customTitleBar = if (SystemInfo.isMacOS && JBR.isWindowDecorationsSupported())
|
||||
JBR.getWindowDecorations().createCustomTitleBar() else null
|
||||
|
||||
companion object {
|
||||
const val DEFAULT_ACTION = "DEFAULT_ACTION"
|
||||
private const val PROCESS_GLOBAL_KEYMAP = "PROCESS_GLOBAL_KEYMAP"
|
||||
}
|
||||
|
||||
|
||||
protected var controlsVisible = true
|
||||
set(value) {
|
||||
field = value
|
||||
titleBar.putProperty("controls.visible", value)
|
||||
if (SystemInfo.isMacOS) {
|
||||
if (customTitleBar != null) {
|
||||
customTitleBar.putProperty("controls.visible", value)
|
||||
} else {
|
||||
NativeMacLibrary.setControlsVisible(this, value)
|
||||
}
|
||||
} else {
|
||||
rootPane.putClientProperty(FlatClientProperties.TITLE_BAR_SHOW_ICONIFFY, value)
|
||||
rootPane.putClientProperty(FlatClientProperties.TITLE_BAR_SHOW_MAXIMIZE, value)
|
||||
rootPane.putClientProperty(FlatClientProperties.TITLE_BAR_SHOW_CLOSE, value)
|
||||
}
|
||||
}
|
||||
|
||||
protected var titleBarHeight = UIManager.getInt("TabbedPane.tabHeight").toFloat()
|
||||
protected var fullWindowContent = false
|
||||
set(value) {
|
||||
titleBar.height = value
|
||||
field = value
|
||||
rootPane.putClientProperty(FlatClientProperties.FULL_WINDOW_CONTENT, value)
|
||||
}
|
||||
|
||||
protected var titleVisible = true
|
||||
set(value) {
|
||||
field = value
|
||||
rootPane.putClientProperty(FlatClientProperties.TITLE_BAR_SHOW_TITLE, value)
|
||||
}
|
||||
|
||||
protected var titleIconVisible = false
|
||||
set(value) {
|
||||
field = value
|
||||
rootPane.putClientProperty(FlatClientProperties.TITLE_BAR_SHOW_ICON, value)
|
||||
}
|
||||
|
||||
|
||||
protected var titleBarHeight = UIManager.getInt("TabbedPane.tabHeight")
|
||||
set(value) {
|
||||
field = value
|
||||
if (SystemInfo.isMacOS) {
|
||||
customTitleBar?.height = height.toFloat()
|
||||
} else {
|
||||
rootPane.putClientProperty(FlatClientProperties.TITLE_BAR_HEIGHT, value)
|
||||
}
|
||||
}
|
||||
|
||||
protected var lostFocusDispose = false
|
||||
@@ -51,25 +82,43 @@ abstract class DialogWrapper(owner: Window?) : JDialog(owner) {
|
||||
super.rootPane.putClientProperty(PROCESS_GLOBAL_KEYMAP, value)
|
||||
}
|
||||
|
||||
init {
|
||||
super.setDefaultCloseOperation(DISPOSE_ON_CLOSE)
|
||||
|
||||
// 使用 FlatLaf 的 TitlePane
|
||||
if (SystemInfo.isWindows || SystemInfo.isLinux) {
|
||||
rootPane.windowDecorationStyle = JRootPane.PLAIN_DIALOG
|
||||
}
|
||||
}
|
||||
|
||||
protected fun init() {
|
||||
|
||||
|
||||
defaultCloseOperation = DISPOSE_ON_CLOSE
|
||||
|
||||
initTitleBar()
|
||||
initEvents()
|
||||
|
||||
if (JBR.isWindowDecorationsSupported()) {
|
||||
if (rootPane.getClientProperty(FlatClientProperties.TITLE_BAR_SHOW_TITLE) != false) {
|
||||
val titlePanel = createTitlePanel()
|
||||
if (titlePanel != null) {
|
||||
rootPanel.add(titlePanel, BorderLayout.NORTH)
|
||||
}
|
||||
val rootPanel = JPanel(BorderLayout())
|
||||
rootPanel.add(createCenterPanel(), BorderLayout.CENTER)
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
val titlePanel = createTitlePanel()
|
||||
if (titlePanel != null) {
|
||||
rootPanel.add(titlePanel, BorderLayout.NORTH)
|
||||
}
|
||||
|
||||
val customTitleBar = this.customTitleBar
|
||||
if (customTitleBar != null) {
|
||||
customTitleBar.putProperty("controls.visible", controlsVisible)
|
||||
customTitleBar.height = titleBarHeight.toFloat()
|
||||
JBR.getWindowDecorations().setCustomTitleBar(this, customTitleBar)
|
||||
}
|
||||
}
|
||||
|
||||
rootPanel.add(createCenterPanel(), BorderLayout.CENTER)
|
||||
|
||||
val southPanel = createSouthPanel()
|
||||
if (southPanel != null) {
|
||||
rootPanel.add(southPanel, BorderLayout.SOUTH)
|
||||
@@ -122,7 +171,7 @@ abstract class DialogWrapper(owner: Window?) : JDialog(owner) {
|
||||
|
||||
val panel = JPanel(BorderLayout())
|
||||
panel.add(titleLabel, BorderLayout.CENTER)
|
||||
panel.preferredSize = Dimension(-1, titleBar.height.toInt())
|
||||
panel.preferredSize = Dimension(-1, titleBarHeight)
|
||||
|
||||
|
||||
return panel
|
||||
@@ -191,30 +240,20 @@ abstract class DialogWrapper(owner: Window?) : JDialog(owner) {
|
||||
}
|
||||
})
|
||||
|
||||
if (SystemInfo.isWindows) {
|
||||
addWindowListener(object : WindowAdapter(), ThemeChangeListener {
|
||||
override fun windowClosed(e: WindowEvent) {
|
||||
ThemeManager.getInstance().removeThemeChangeListener(this)
|
||||
}
|
||||
|
||||
override fun windowOpened(e: WindowEvent) {
|
||||
onChanged()
|
||||
ThemeManager.getInstance().addThemeChangeListener(this)
|
||||
}
|
||||
|
||||
override fun onChanged() {
|
||||
titleBar.putProperty("controls.dark", FlatLaf.isLafDark())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun initTitleBar() {
|
||||
titleBar.height = titleBarHeight
|
||||
titleBar.putProperty("controls.visible", controlsVisible)
|
||||
if (JBR.isWindowDecorationsSupported()) {
|
||||
JBR.getWindowDecorations().setCustomTitleBar(this, titleBar)
|
||||
override fun addNotify() {
|
||||
super.addNotify()
|
||||
|
||||
// 显示后触发一次重绘制
|
||||
if (SystemInfo.isWindows || SystemInfo.isLinux) {
|
||||
this.controlsVisible = controlsVisible
|
||||
this.titleBarHeight = titleBarHeight
|
||||
this.titleIconVisible = titleIconVisible
|
||||
this.titleVisible = titleVisible
|
||||
this.fullWindowContent = fullWindowContent
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected open fun doOKAction() {
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
package app.termora
|
||||
|
||||
import com.formdev.flatlaf.extras.components.FlatTextField
|
||||
import org.apache.commons.lang3.StringUtils
|
||||
import java.awt.Window
|
||||
import java.awt.event.KeyAdapter
|
||||
import java.awt.event.KeyEvent
|
||||
import javax.swing.BorderFactory
|
||||
import javax.swing.JComponent
|
||||
import javax.swing.UIManager
|
||||
|
||||
class InputDialog(
|
||||
owner: Window,
|
||||
title: String,
|
||||
text: String = StringUtils.EMPTY,
|
||||
placeholderText: String = StringUtils.EMPTY
|
||||
) : DialogWrapper(owner) {
|
||||
private val textField = FlatTextField()
|
||||
private var text: String? = null
|
||||
|
||||
init {
|
||||
setSize(340, 60)
|
||||
setLocationRelativeTo(owner)
|
||||
|
||||
super.setTitle(title)
|
||||
|
||||
isResizable = false
|
||||
isModal = true
|
||||
controlsVisible = false
|
||||
titleBarHeight = UIManager.getInt("TabbedPane.tabHeight") * 0.8f
|
||||
|
||||
|
||||
textField.placeholderText = placeholderText
|
||||
textField.text = text
|
||||
textField.addKeyListener(object : KeyAdapter() {
|
||||
override fun keyPressed(e: KeyEvent) {
|
||||
if (e.keyCode == KeyEvent.VK_ENTER) {
|
||||
if (textField.text.isBlank()) {
|
||||
return
|
||||
}
|
||||
doOKAction()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
init()
|
||||
}
|
||||
|
||||
override fun createCenterPanel(): JComponent {
|
||||
textField.background = UIManager.getColor("window")
|
||||
textField.border = BorderFactory.createEmptyBorder(0, 13, 0, 13)
|
||||
|
||||
return textField
|
||||
}
|
||||
|
||||
fun getText(): String? {
|
||||
isVisible = true
|
||||
return text
|
||||
}
|
||||
|
||||
override fun doCancelAction() {
|
||||
text = null
|
||||
super.doCancelAction()
|
||||
}
|
||||
|
||||
override fun doOKAction() {
|
||||
text = textField.text
|
||||
super.doOKAction()
|
||||
}
|
||||
|
||||
override fun createSouthPanel(): JComponent? {
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
package app.termora
|
||||
|
||||
import com.formdev.flatlaf.FlatClientProperties
|
||||
import com.jetbrains.JBR
|
||||
import com.jetbrains.WindowDecorations.CustomTitleBar
|
||||
import java.awt.Rectangle
|
||||
import java.awt.Window
|
||||
import javax.swing.RootPaneContainer
|
||||
|
||||
class LogicCustomTitleBar(private val titleBar: CustomTitleBar) : CustomTitleBar {
|
||||
companion object {
|
||||
fun createCustomTitleBar(rootPaneContainer: RootPaneContainer): CustomTitleBar {
|
||||
if (!JBR.isWindowDecorationsSupported()) {
|
||||
return LogicCustomTitleBar(object : CustomTitleBar {
|
||||
override fun getHeight(): Float {
|
||||
val bounds = rootPaneContainer.rootPane
|
||||
.getClientProperty(FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_BOUNDS)
|
||||
if (bounds is Rectangle) {
|
||||
return bounds.height.toFloat()
|
||||
}
|
||||
return 0f
|
||||
}
|
||||
|
||||
override fun setHeight(height: Float) {
|
||||
rootPaneContainer.rootPane.putClientProperty(
|
||||
FlatClientProperties.TITLE_BAR_HEIGHT,
|
||||
height.toInt()
|
||||
)
|
||||
}
|
||||
|
||||
override fun getProperties(): MutableMap<String, Any> {
|
||||
return mutableMapOf()
|
||||
}
|
||||
|
||||
override fun putProperties(m: MutableMap<String, *>?) {
|
||||
|
||||
}
|
||||
|
||||
override fun putProperty(key: String?, value: Any?) {
|
||||
if (key == "controls.visible" && value is Boolean) {
|
||||
rootPaneContainer.rootPane.putClientProperty(
|
||||
FlatClientProperties.TITLE_BAR_SHOW_CLOSE,
|
||||
value
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getLeftInset(): Float {
|
||||
return 0f
|
||||
}
|
||||
|
||||
override fun getRightInset(): Float {
|
||||
val bounds = rootPaneContainer.rootPane
|
||||
.getClientProperty(FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_BOUNDS)
|
||||
if (bounds is Rectangle) {
|
||||
return bounds.width.toFloat()
|
||||
}
|
||||
return 0f
|
||||
}
|
||||
|
||||
override fun forceHitTest(client: Boolean) {
|
||||
|
||||
}
|
||||
|
||||
override fun getContainingWindow(): Window {
|
||||
return rootPaneContainer as Window
|
||||
}
|
||||
})
|
||||
}
|
||||
return JBR.getWindowDecorations().createCustomTitleBar()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getHeight(): Float {
|
||||
return titleBar.height
|
||||
}
|
||||
|
||||
override fun setHeight(height: Float) {
|
||||
titleBar.height = height
|
||||
}
|
||||
|
||||
override fun getProperties(): MutableMap<String, Any> {
|
||||
return titleBar.properties
|
||||
}
|
||||
|
||||
override fun putProperties(m: MutableMap<String, *>?) {
|
||||
titleBar.putProperties(m)
|
||||
}
|
||||
|
||||
override fun putProperty(key: String?, value: Any?) {
|
||||
titleBar.putProperty(key, value)
|
||||
}
|
||||
|
||||
override fun getLeftInset(): Float {
|
||||
return titleBar.leftInset
|
||||
}
|
||||
|
||||
override fun getRightInset(): Float {
|
||||
return titleBar.rightInset
|
||||
}
|
||||
|
||||
override fun forceHitTest(client: Boolean) {
|
||||
titleBar.forceHitTest(client)
|
||||
}
|
||||
|
||||
override fun getContainingWindow(): Window {
|
||||
return titleBar.containingWindow
|
||||
}
|
||||
}
|
||||
11
src/main/kotlin/app/termora/MyFlatRootPaneUI.kt
Normal file
11
src/main/kotlin/app/termora/MyFlatRootPaneUI.kt
Normal file
@@ -0,0 +1,11 @@
|
||||
package app.termora
|
||||
|
||||
import com.formdev.flatlaf.ui.FlatRootPaneUI
|
||||
import com.formdev.flatlaf.ui.FlatTitlePane
|
||||
|
||||
class MyFlatRootPaneUI : FlatRootPaneUI() {
|
||||
|
||||
fun getTitlePane(): FlatTitlePane? {
|
||||
return super.titlePane
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
package app.termora
|
||||
|
||||
import app.termora.native.osx.NativeMacLibrary
|
||||
import com.formdev.flatlaf.FlatClientProperties
|
||||
import com.formdev.flatlaf.extras.components.FlatTextPane
|
||||
import com.formdev.flatlaf.util.SystemInfo
|
||||
import com.jetbrains.JBR
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.swing.Swing
|
||||
import org.apache.commons.lang3.StringUtils
|
||||
import java.awt.BorderLayout
|
||||
import java.awt.Component
|
||||
import java.awt.Desktop
|
||||
@@ -113,6 +115,36 @@ object OptionPane {
|
||||
dialog.dispose()
|
||||
}
|
||||
|
||||
fun showInputDialog(
|
||||
parentComponent: Component?,
|
||||
title: String = UIManager.getString("OptionPane.messageDialogTitle"),
|
||||
value: String = StringUtils.EMPTY,
|
||||
placeholder: String = StringUtils.EMPTY,
|
||||
): String? {
|
||||
val pane = JOptionPane(StringUtils.EMPTY, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION)
|
||||
val dialog = initDialog(pane.createDialog(parentComponent, title))
|
||||
pane.wantsInput = true
|
||||
pane.initialSelectionValue = value
|
||||
|
||||
val textField = SwingUtils.getDescendantsOfType(JTextField::class.java, pane, true).firstOrNull()
|
||||
if (textField?.name == "OptionPane.textField") {
|
||||
textField.border = BorderFactory.createCompoundBorder(
|
||||
BorderFactory.createMatteBorder(0, 0, 1, 0, DynamicColor.BorderColor),
|
||||
BorderFactory.createEmptyBorder(0, 0, 2, 0)
|
||||
)
|
||||
textField.background = UIManager.getColor("window")
|
||||
textField.putClientProperty(FlatClientProperties.PLACEHOLDER_TEXT, placeholder)
|
||||
}
|
||||
|
||||
dialog.isVisible = true
|
||||
dialog.dispose()
|
||||
|
||||
val inputValue = pane.inputValue
|
||||
if (inputValue == JOptionPane.UNINITIALIZED_VALUE) return null
|
||||
|
||||
return inputValue as? String
|
||||
}
|
||||
|
||||
fun openFileInFolder(
|
||||
parentComponent: Component,
|
||||
file: File,
|
||||
@@ -140,14 +172,31 @@ object OptionPane {
|
||||
}
|
||||
|
||||
private fun initDialog(dialog: JDialog): JDialog {
|
||||
if (SystemInfo.isWindows || SystemInfo.isLinux) {
|
||||
dialog.rootPane.putClientProperty(FlatClientProperties.TITLE_BAR_SHOW_CLOSE, false)
|
||||
dialog.rootPane.putClientProperty(
|
||||
FlatClientProperties.TITLE_BAR_HEIGHT,
|
||||
UIManager.getInt("TabbedPane.tabHeight")
|
||||
)
|
||||
} else if (SystemInfo.isMacOS) {
|
||||
dialog.rootPane.putClientProperty("apple.awt.windowTitleVisible", false)
|
||||
dialog.rootPane.putClientProperty("apple.awt.fullWindowContent", true)
|
||||
dialog.rootPane.putClientProperty("apple.awt.transparentTitleBar", true)
|
||||
dialog.rootPane.putClientProperty(
|
||||
FlatClientProperties.MACOS_WINDOW_BUTTONS_SPACING,
|
||||
FlatClientProperties.MACOS_WINDOW_BUTTONS_SPACING_MEDIUM
|
||||
)
|
||||
|
||||
if (JBR.isWindowDecorationsSupported()) {
|
||||
|
||||
val windowDecorations = JBR.getWindowDecorations()
|
||||
val titleBar = windowDecorations.createCustomTitleBar()
|
||||
titleBar.putProperty("controls.visible", false)
|
||||
titleBar.height = UIManager.getInt("TabbedPane.tabHeight") - if (SystemInfo.isMacOS) 10f else 6f
|
||||
windowDecorations.setCustomTitleBar(dialog, titleBar)
|
||||
val height = UIManager.getInt("TabbedPane.tabHeight") - 10
|
||||
if (JBR.isWindowDecorationsSupported()) {
|
||||
val customTitleBar = JBR.getWindowDecorations().createCustomTitleBar()
|
||||
customTitleBar.putProperty("controls.visible", false)
|
||||
customTitleBar.height = height.toFloat()
|
||||
JBR.getWindowDecorations().setCustomTitleBar(dialog, customTitleBar)
|
||||
} else {
|
||||
NativeMacLibrary.setControlsVisible(dialog, false)
|
||||
}
|
||||
|
||||
val label = JLabel(dialog.title)
|
||||
label.putClientProperty(FlatClientProperties.STYLE, "font: bold")
|
||||
@@ -155,11 +204,9 @@ object OptionPane {
|
||||
box.add(Box.createHorizontalGlue())
|
||||
box.add(label)
|
||||
box.add(Box.createHorizontalGlue())
|
||||
box.preferredSize = Dimension(-1, titleBar.height.toInt())
|
||||
|
||||
box.preferredSize = Dimension(-1, height)
|
||||
dialog.contentPane.add(box, BorderLayout.NORTH)
|
||||
}
|
||||
|
||||
return dialog
|
||||
}
|
||||
}
|
||||
@@ -190,12 +190,11 @@ class TerminalTabbed(
|
||||
val rename = popupMenu.add(I18n.getString("termora.tabbed.contextmenu.rename"))
|
||||
rename.addActionListener {
|
||||
if (tabIndex > 0) {
|
||||
val dialog = InputDialog(
|
||||
val text = OptionPane.showInputDialog(
|
||||
SwingUtilities.getWindowAncestor(this),
|
||||
title = rename.text,
|
||||
text = tabbedPane.getTitleAt(tabIndex),
|
||||
value = tabbedPane.getTitleAt(tabIndex)
|
||||
)
|
||||
val text = dialog.getText()
|
||||
if (!text.isNullOrBlank()) {
|
||||
tabbedPane.setTitleAt(tabIndex, text)
|
||||
c.putClientProperty(titleProperty, text)
|
||||
|
||||
@@ -7,21 +7,19 @@ import app.termora.actions.DataProviders
|
||||
import app.termora.sftp.SFTPTab
|
||||
import app.termora.terminal.DataKey
|
||||
import com.formdev.flatlaf.FlatClientProperties
|
||||
import com.formdev.flatlaf.FlatLaf
|
||||
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.Box
|
||||
import javax.swing.JFrame
|
||||
import javax.swing.SwingUtilities
|
||||
import javax.swing.*
|
||||
import javax.swing.SwingUtilities.isEventDispatchThread
|
||||
import javax.swing.UIManager
|
||||
import kotlin.math.max
|
||||
|
||||
fun assertEventDispatchThread() {
|
||||
if (!isEventDispatchThread()) throw WrongThreadException("AWT EventQueue")
|
||||
@@ -33,14 +31,13 @@ class TermoraFrame : JFrame(), DataProvider {
|
||||
|
||||
private val id = UUID.randomUUID().toString()
|
||||
private val windowScope = ApplicationScope.forWindowScope(this)
|
||||
private val titleBar = LogicCustomTitleBar.createCustomTitleBar(this)
|
||||
private val tabbedPane = MyTabbedPane()
|
||||
private val toolbar = TermoraToolBar(windowScope, titleBar, tabbedPane)
|
||||
private val toolbar = TermoraToolBar(windowScope, this, tabbedPane)
|
||||
private val terminalTabbed = TerminalTabbed(windowScope, toolbar, tabbedPane)
|
||||
private val isWindowDecorationsSupported by lazy { JBR.isWindowDecorationsSupported() }
|
||||
private val dataProviderSupport = DataProviderSupport()
|
||||
private val welcomePanel = WelcomePanel(windowScope)
|
||||
private val sftp get() = Database.getDatabase().sftp
|
||||
private val myUI = MyFlatRootPaneUI()
|
||||
|
||||
|
||||
init {
|
||||
@@ -49,44 +46,146 @@ class TermoraFrame : JFrame(), DataProvider {
|
||||
}
|
||||
|
||||
private fun initEvents() {
|
||||
if (SystemInfo.isLinux) {
|
||||
val mouseAdapter = object : MouseAdapter() {
|
||||
override fun mouseClicked(e: MouseEvent) {
|
||||
getMouseHandler()?.mouseClicked(e)
|
||||
}
|
||||
|
||||
forceHitTest()
|
||||
override fun mousePressed(e: MouseEvent) {
|
||||
getMouseHandler()?.mousePressed(e)
|
||||
}
|
||||
|
||||
// macos 需要判断是否全部删除
|
||||
// 当 Tab 为 0 的时候,需要加一个边距,避开控制栏
|
||||
if (SystemInfo.isMacOS && isWindowDecorationsSupported) {
|
||||
tabbedPane.addChangeListener {
|
||||
tabbedPane.leadingComponent = if (tabbedPane.tabCount == 0) {
|
||||
Box.createHorizontalStrut(titleBar.leftInset.toInt())
|
||||
} else {
|
||||
null
|
||||
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()
|
||||
|
||||
// 监听主题变化 需要动态修改控制栏颜色
|
||||
if (SystemInfo.isWindows && isWindowDecorationsSupported) {
|
||||
ThemeManager.getInstance().addThemeChangeListener(object : ThemeChangeListener {
|
||||
override fun onChanged() {
|
||||
titleBar.putProperty("controls.dark", FlatLaf.isLafDark())
|
||||
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() {
|
||||
if (isWindowDecorationsSupported) {
|
||||
titleBar.height = UIManager.getInt("TabbedPane.tabHeight").toFloat()
|
||||
titleBar.putProperty("controls.dark", FlatLaf.isLafDark())
|
||||
JBR.getWindowDecorations().setCustomTitleBar(this, titleBar)
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
if (SystemInfo.isLinux) {
|
||||
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_HEIGHT, UIManager.getInt("TabbedPane.tabHeight"))
|
||||
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) {
|
||||
@@ -102,88 +201,21 @@ class TermoraFrame : JFrame(), DataProvider {
|
||||
terminalTabbed.addTerminalTab(welcomePanel)
|
||||
|
||||
// 下一次事件循环检测是否固定 SFTP
|
||||
SwingUtilities.invokeLater {
|
||||
if (sftp.pinTab) {
|
||||
if (sftp.pinTab) {
|
||||
SwingUtilities.invokeLater {
|
||||
terminalTabbed.addTerminalTab(SFTPTab(), false)
|
||||
}
|
||||
}
|
||||
|
||||
// macOS 要避开左边的控制栏
|
||||
if (SystemInfo.isMacOS) {
|
||||
val left = max(titleBar.leftInset.toInt(), 76)
|
||||
if (tabbedPane.tabCount == 0) {
|
||||
tabbedPane.leadingComponent = Box.createHorizontalStrut(left)
|
||||
} else {
|
||||
tabbedPane.tabAreaInsets = Insets(0, left, 0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
Disposer.register(windowScope, terminalTabbed)
|
||||
add(terminalTabbed)
|
||||
add(terminalTabbed, BorderLayout.CENTER)
|
||||
|
||||
dataProviderSupport.addData(DataProviders.TabbedPane, tabbedPane)
|
||||
dataProviderSupport.addData(DataProviders.TermoraFrame, this)
|
||||
dataProviderSupport.addData(DataProviders.WindowScope, windowScope)
|
||||
}
|
||||
|
||||
|
||||
private fun forceHitTest() {
|
||||
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
|
||||
}
|
||||
}
|
||||
titleBar.forceHitTest(false)
|
||||
}
|
||||
|
||||
override fun mouseClicked(e: MouseEvent) {
|
||||
hit(e)
|
||||
}
|
||||
|
||||
override fun mousePressed(e: MouseEvent) {
|
||||
if (e.source == toolbar.getJToolBar()) {
|
||||
if (!isWindowDecorationsSupported && SwingUtilities.isLeftMouseButton(e)) {
|
||||
if (JBR.isWindowMoveSupported()) {
|
||||
JBR.getWindowMove().startMovingTogetherWithMouse(this@TermoraFrame, e.button)
|
||||
}
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
override fun <T : Any> getData(dataKey: DataKey<T>): T? {
|
||||
return dataProviderSupport.getData(dataKey)
|
||||
?: terminalTabbed.getData(dataKey)
|
||||
@@ -204,5 +236,22 @@ class TermoraFrame : JFrame(), DataProvider {
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -4,13 +4,13 @@ import app.termora.Application.ohMyJson
|
||||
import app.termora.actions.*
|
||||
import app.termora.findeverywhere.FindEverywhereAction
|
||||
import app.termora.snippet.SnippetAction
|
||||
import com.formdev.flatlaf.FlatClientProperties
|
||||
import com.formdev.flatlaf.extras.components.FlatTabbedPane
|
||||
import com.formdev.flatlaf.util.SystemInfo
|
||||
import com.jetbrains.WindowDecorations
|
||||
import kotlinx.serialization.Serializable
|
||||
import org.apache.commons.lang3.StringUtils
|
||||
import org.jdesktop.swingx.action.ActionContainerFactory
|
||||
import java.awt.Insets
|
||||
import java.awt.Rectangle
|
||||
import java.awt.event.ComponentAdapter
|
||||
import java.awt.event.ComponentEvent
|
||||
import javax.swing.Box
|
||||
@@ -25,7 +25,7 @@ data class ToolBarAction(
|
||||
|
||||
class TermoraToolBar(
|
||||
private val windowScope: WindowScope,
|
||||
private val titleBar: WindowDecorations.CustomTitleBar,
|
||||
private val frame: TermoraFrame,
|
||||
private val tabbedPane: FlatTabbedPane
|
||||
) {
|
||||
private val properties by lazy { Database.getDatabase().properties }
|
||||
@@ -155,14 +155,11 @@ class TermoraToolBar(
|
||||
}
|
||||
|
||||
fun adjust() {
|
||||
if (SystemInfo.isMacOS) {
|
||||
val left = titleBar.leftInset.toInt()
|
||||
if (tabbedPane.tabAreaInsets.left != left) {
|
||||
tabbedPane.tabAreaInsets = Insets(0, left, 0, 0)
|
||||
}
|
||||
} else if (SystemInfo.isWindows || SystemInfo.isLinux) {
|
||||
|
||||
val right = titleBar.rightInset.toInt()
|
||||
if (SystemInfo.isWindows || SystemInfo.isLinux) {
|
||||
val rectangle =
|
||||
frame.rootPane.getClientProperty(FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_BOUNDS)
|
||||
as? Rectangle ?: return
|
||||
val right = rectangle.width
|
||||
val toolbar = this@MyToolBar
|
||||
for (i in 0 until toolbar.componentCount) {
|
||||
val c = toolbar.getComponent(i)
|
||||
|
||||
@@ -7,9 +7,7 @@ import app.termora.WindowScope
|
||||
import app.termora.actions.AnAction
|
||||
import app.termora.actions.AnActionEvent
|
||||
import app.termora.macro.MacroFindEverywhereProvider
|
||||
import com.formdev.flatlaf.FlatClientProperties
|
||||
import com.formdev.flatlaf.extras.components.FlatTextField
|
||||
import com.jetbrains.JBR
|
||||
import java.awt.BorderLayout
|
||||
import java.awt.Dimension
|
||||
import java.awt.Insets
|
||||
@@ -45,17 +43,10 @@ class FindEverywhere(owner: Window, windowScope: WindowScope) : DialogWrapper(ow
|
||||
minimumSize = Dimension(size.width / 2, size.height / 2)
|
||||
isModal = false
|
||||
lostFocusDispose = true
|
||||
controlsVisible = false
|
||||
defaultCloseOperation = WindowConstants.DISPOSE_ON_CLOSE
|
||||
setLocationRelativeTo(null)
|
||||
|
||||
// 不支持装饰,铺满
|
||||
if (!JBR.isWindowDecorationsSupported()) {
|
||||
rootPane.putClientProperty(FlatClientProperties.FULL_WINDOW_CONTENT, true)
|
||||
rootPane.putClientProperty(FlatClientProperties.TITLE_BAR_SHOW_CLOSE, false)
|
||||
}
|
||||
|
||||
rootPane.background = DynamicColor("desktop")
|
||||
val desktopBackground = DynamicColor("desktop")
|
||||
centerPanel.background = DynamicColor("desktop")
|
||||
centerPanel.border = BorderFactory.createEmptyBorder(12, 12, 12, 12)
|
||||
|
||||
@@ -70,7 +61,7 @@ class FindEverywhere(owner: Window, windowScope: WindowScope) : DialogWrapper(ow
|
||||
resultList.isRolloverEnabled = false
|
||||
resultList.selectionMode = ListSelectionModel.SINGLE_SELECTION
|
||||
resultList.border = BorderFactory.createEmptyBorder(5, 0, 0, 0)
|
||||
resultList.background = rootPane.background
|
||||
resultList.background = desktopBackground
|
||||
|
||||
|
||||
val scrollPane = JScrollPane(resultList)
|
||||
@@ -226,5 +217,11 @@ class FindEverywhere(owner: Window, windowScope: WindowScope) : DialogWrapper(ow
|
||||
super.setVisible(visible)
|
||||
}
|
||||
|
||||
override fun addNotify() {
|
||||
super.addNotify()
|
||||
|
||||
controlsVisible = false
|
||||
fullWindowContent = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -119,10 +119,11 @@ class KeymapPanel : JPanel(BorderLayout()) {
|
||||
val keymap = getCurrentKeymap()
|
||||
val index = keymapComboBox.selectedIndex
|
||||
if (keymap != null && !keymap.isReadonly && index >= 0) {
|
||||
val text = InputDialog(
|
||||
val text = OptionPane.showInputDialog(
|
||||
SwingUtilities.getWindowAncestor(this@KeymapPanel),
|
||||
title = renameBtn.toolTipText, text = keymap.name
|
||||
).getText()
|
||||
title = renameBtn.toolTipText,
|
||||
value = keymap.name
|
||||
)
|
||||
if (!text.isNullOrBlank()) {
|
||||
if (text != keymap.name) {
|
||||
keymapManager.removeKeymap(keymap.name)
|
||||
|
||||
@@ -103,7 +103,9 @@ class KeyManagerPanel : JPanel(BorderLayout()) {
|
||||
|
||||
private fun initEvents() {
|
||||
generateBtn.addActionListener {
|
||||
val dialog = GenerateKeyDialog(SwingUtilities.getWindowAncestor(this))
|
||||
val owner = SwingUtilities.getWindowAncestor(this)
|
||||
val dialog = GenerateKeyDialog(owner)
|
||||
dialog.setLocationRelativeTo(owner)
|
||||
dialog.isVisible = true
|
||||
if (dialog.ohKeyPair != OhKeyPair.empty) {
|
||||
val keyPair = dialog.ohKeyPair
|
||||
@@ -142,12 +144,14 @@ class KeyManagerPanel : JPanel(BorderLayout()) {
|
||||
editBtn.addActionListener {
|
||||
val row = keyPairTable.selectedRow
|
||||
if (row >= 0) {
|
||||
val owner = SwingUtilities.getWindowAncestor(this)
|
||||
var ohKeyPair = keyPairTableModel.getOhKeyPair(row)
|
||||
val dialog = GenerateKeyDialog(
|
||||
SwingUtilities.getWindowAncestor(this),
|
||||
owner,
|
||||
ohKeyPair,
|
||||
true
|
||||
)
|
||||
dialog.setLocationRelativeTo(owner)
|
||||
dialog.title = ohKeyPair.name
|
||||
dialog.isVisible = true
|
||||
ohKeyPair = dialog.ohKeyPair
|
||||
@@ -342,7 +346,6 @@ class KeyManagerPanel : JPanel(BorderLayout()) {
|
||||
|
||||
pack()
|
||||
size = Dimension(UIManager.getInt("Dialog.width") - 300, size.height)
|
||||
setLocationRelativeTo(null)
|
||||
|
||||
}
|
||||
|
||||
@@ -354,7 +357,7 @@ class KeyManagerPanel : JPanel(BorderLayout()) {
|
||||
|
||||
var rows = 1
|
||||
val step = 2
|
||||
return FormBuilder.create().layout(layout).padding("0dlu, $formMargin, $formMargin, $formMargin")
|
||||
return FormBuilder.create().layout(layout).padding("2dlu, $formMargin, $formMargin, $formMargin")
|
||||
.add("${I18n.getString("termora.keymgr.table.type")}:").xy(1, rows)
|
||||
.add(typeComboBox).xy(3, rows).apply { rows += step }
|
||||
.add("${I18n.getString("termora.keymgr.table.length")}:").xy(1, rows)
|
||||
@@ -512,7 +515,7 @@ class KeyManagerPanel : JPanel(BorderLayout()) {
|
||||
|
||||
var rows = 1
|
||||
val step = 2
|
||||
return FormBuilder.create().layout(layout).padding("0dlu, $formMargin, $formMargin, $formMargin")
|
||||
return FormBuilder.create().layout(layout).padding("2dlu, $formMargin, $formMargin, $formMargin")
|
||||
.add("File:").xy(1, rows)
|
||||
.add(fileTextField).xy(3, rows).apply { rows += step }
|
||||
.add("${I18n.getString("termora.keymgr.table.type")}:").xy(1, rows)
|
||||
@@ -587,8 +590,10 @@ class KeyManagerPanel : JPanel(BorderLayout()) {
|
||||
try {
|
||||
val provider = FileKeyPairProvider(file.toPath())
|
||||
provider.passwordFinder = FilePasswordProvider { _, _, _ ->
|
||||
val dialog = InputDialog(owner = this@ImportKeyDialog, title = "Password")
|
||||
dialog.getText() ?: String()
|
||||
OptionPane.showInputDialog(
|
||||
SwingUtilities.getWindowAncestor(this),
|
||||
title = I18n.getString("termora.new-host.general.password"),
|
||||
) ?: String()
|
||||
}
|
||||
val keyPair = provider.loadKeys(null).firstOrNull()
|
||||
?: throw IllegalStateException("Failed to load the key file")
|
||||
|
||||
@@ -83,8 +83,11 @@ class MacroDialog(owner: Window) : DialogWrapper(owner) {
|
||||
val index = list.selectedIndex
|
||||
if (index >= 0) {
|
||||
val macro = model.getElementAt(index)
|
||||
val dialog = InputDialog(owner = this, title = macro.name, text = macro.name)
|
||||
val text = dialog.getText() ?: String()
|
||||
val text = OptionPane.showInputDialog(
|
||||
this,
|
||||
title = macro.name,
|
||||
value = macro.name
|
||||
) ?: String()
|
||||
if (text.isNotBlank()) {
|
||||
val newMacro = macro.copy(name = text)
|
||||
macroManager.addMacro(newMacro)
|
||||
|
||||
51
src/main/kotlin/app/termora/native/osx/NativeMacLibrary.kt
Normal file
51
src/main/kotlin/app/termora/native/osx/NativeMacLibrary.kt
Normal file
@@ -0,0 +1,51 @@
|
||||
package app.termora.native.osx
|
||||
|
||||
import de.jangassen.jfa.foundation.Foundation
|
||||
import de.jangassen.jfa.foundation.ID
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.awt.Component
|
||||
import java.awt.Window
|
||||
|
||||
object NativeMacLibrary {
|
||||
private val log = LoggerFactory.getLogger(NativeMacLibrary::class.java)
|
||||
|
||||
fun getNSWindow(window: Window): Long? {
|
||||
try {
|
||||
val peerField = Component::class.java.getDeclaredField("peer") ?: return null
|
||||
peerField.isAccessible = true
|
||||
val peer = peerField.get(window) ?: return null
|
||||
|
||||
val platformWindowField = peer.javaClass.getDeclaredField("platformWindow") ?: return null
|
||||
platformWindowField.isAccessible = true
|
||||
val platformWindow = platformWindowField.get(peer)
|
||||
|
||||
val ptrField = Class.forName("sun.lwawt.macosx.CFRetainedResource")
|
||||
.getDeclaredField("ptr") ?: return null
|
||||
ptrField.isAccessible = true
|
||||
return ptrField.get(platformWindow) as Long
|
||||
} catch (e: Exception) {
|
||||
if (log.isErrorEnabled) {
|
||||
log.error(e.message, e)
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
fun setControlsVisible(window: Window, visible: Boolean) {
|
||||
val nsWindow = ID(getNSWindow(window) ?: return)
|
||||
try {
|
||||
Foundation.executeOnMainThread(true, true) {
|
||||
for (i in 0..2) {
|
||||
val button = Foundation.invoke(nsWindow, "standardWindowButton:", i)
|
||||
Foundation.invoke(button, "setHidden:", !visible)
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
if (log.isErrorEnabled) {
|
||||
log.error(e.message, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -414,12 +414,11 @@ class FileSystemViewTable(
|
||||
val index = selectedRow
|
||||
if (index < 0) return
|
||||
val attr = model.getAttr(index)
|
||||
val dialog = InputDialog(
|
||||
val text = OptionPane.showInputDialog(
|
||||
owner,
|
||||
title = attr.name,
|
||||
text = attr.name,
|
||||
)
|
||||
val text = dialog.getText() ?: return
|
||||
value = attr.name,
|
||||
title = I18n.getString("termora.transport.table.contextmenu.rename")
|
||||
) ?: return
|
||||
if (text.isBlank() || text == attr.name) return
|
||||
if (model.getPathNames().contains(text)) {
|
||||
OptionPane.showMessageDialog(
|
||||
@@ -544,12 +543,7 @@ class FileSystemViewTable(
|
||||
private fun newFolderOrFile(isFile: Boolean) {
|
||||
val name = if (isFile) I18n.getString("termora.transport.table.contextmenu.new.file")
|
||||
else I18n.getString("termora.welcome.contextmenu.new.folder.name")
|
||||
val dialog = InputDialog(
|
||||
owner,
|
||||
title = name,
|
||||
text = name,
|
||||
)
|
||||
val text = dialog.getText() ?: return
|
||||
val text = OptionPane.showInputDialog(owner, title = name, value = name) ?: return
|
||||
if (text.isBlank()) return
|
||||
if (model.getPathNames().contains(text)) {
|
||||
OptionPane.showMessageDialog(
|
||||
|
||||
Reference in New Issue
Block a user