feat: confirm tab close (#605)

This commit is contained in:
hstyi
2025-05-30 09:48:48 +08:00
committed by GitHub
parent 7a24e34695
commit 17859be3c5
8 changed files with 59 additions and 7 deletions

View File

@@ -648,6 +648,11 @@ class Database private constructor(private val env: Environment) : Disposable {
*/ */
var backgroundRunning by BooleanPropertyDelegate(false) var backgroundRunning by BooleanPropertyDelegate(false)
/**
* 标签关闭前确认
*/
var confirmTabClose by BooleanPropertyDelegate(false)
/** /**
* 背景图片的地址 * 背景图片的地址
*/ */

View File

@@ -223,10 +223,9 @@ class SSHTerminalTab(windowScope: WindowScope, host: Host) :
} }
} }
override fun willBeClose(): Boolean { override fun beforeClose() {
// 保存窗口状态 // 保存窗口状态
terminalPanel.storeVisualWindows(host.id) terminalPanel.storeVisualWindows(host.id)
return super.willBeClose()
} }
private inner class MySessionListener : SessionListener, Disposable { private inner class MySessionListener : SessionListener, Disposable {

View File

@@ -132,6 +132,7 @@ class SettingsOptionsPane : OptionsPane() {
val themeComboBox = FlatComboBox<String>() val themeComboBox = FlatComboBox<String>()
val languageComboBox = FlatComboBox<String>() val languageComboBox = FlatComboBox<String>()
val backgroundComBoBox = YesOrNoComboBox() val backgroundComBoBox = YesOrNoComboBox()
val confirmTabCloseComBoBox = YesOrNoComboBox()
val followSystemCheckBox = JCheckBox(I18n.getString("termora.settings.appearance.follow-system")) val followSystemCheckBox = JCheckBox(I18n.getString("termora.settings.appearance.follow-system"))
val preferredThemeBtn = JButton(Icons.settings) val preferredThemeBtn = JButton(Icons.settings)
val opacitySpinner = NumberSpinner(100, 0, 100) val opacitySpinner = NumberSpinner(100, 0, 100)
@@ -180,6 +181,7 @@ class SettingsOptionsPane : OptionsPane() {
followSystemCheckBox.isSelected = appearance.followSystem followSystemCheckBox.isSelected = appearance.followSystem
preferredThemeBtn.isEnabled = followSystemCheckBox.isSelected preferredThemeBtn.isEnabled = followSystemCheckBox.isSelected
backgroundComBoBox.selectedItem = appearance.backgroundRunning backgroundComBoBox.selectedItem = appearance.backgroundRunning
confirmTabCloseComBoBox.selectedItem = appearance.confirmTabClose
themeComboBox.isEnabled = !followSystemCheckBox.isSelected themeComboBox.isEnabled = !followSystemCheckBox.isSelected
themeManager.themes.keys.forEach { themeComboBox.addItem(it) } themeManager.themes.keys.forEach { themeComboBox.addItem(it) }
@@ -230,6 +232,13 @@ class SettingsOptionsPane : OptionsPane() {
} }
} }
confirmTabCloseComBoBox.addItemListener {
if (it.stateChange == ItemEvent.SELECTED) {
appearance.confirmTabClose = confirmTabCloseComBoBox.selectedItem as Boolean
}
}
followSystemCheckBox.addActionListener { followSystemCheckBox.addActionListener {
appearance.followSystem = followSystemCheckBox.isSelected appearance.followSystem = followSystemCheckBox.isSelected
themeComboBox.isEnabled = !followSystemCheckBox.isSelected themeComboBox.isEnabled = !followSystemCheckBox.isSelected
@@ -368,7 +377,7 @@ class SettingsOptionsPane : OptionsPane() {
private fun getFormPanel(): JPanel { private fun getFormPanel(): JPanel {
val layout = FormLayout( val layout = FormLayout(
"left:pref, $formMargin, default:grow, $formMargin, default, default:grow", "left:pref, $formMargin, default:grow, $formMargin, default, default:grow",
"pref, $formMargin, pref, $formMargin, pref, $formMargin, pref, $formMargin, pref" "pref, $formMargin, pref, $formMargin, pref, $formMargin, pref, $formMargin, pref, $formMargin, pref"
) )
val box = FlatToolBar() val box = FlatToolBar()
box.add(followSystemCheckBox) box.add(followSystemCheckBox)
@@ -401,7 +410,13 @@ class SettingsOptionsPane : OptionsPane() {
.add(opacitySpinner).xy(3, rows).apply { rows += step } .add(opacitySpinner).xy(3, rows).apply { rows += step }
builder.add("${I18n.getString("termora.settings.appearance.background-running")}:").xy(1, rows) builder.add("${I18n.getString("termora.settings.appearance.background-running")}:").xy(1, rows)
.add(backgroundComBoBox).xy(3, rows) .add(backgroundComBoBox).xy(3, rows).apply { rows += step }
val confirmTabCloseBox = Box.createHorizontalBox()
confirmTabCloseBox.add(JLabel("${I18n.getString("termora.settings.appearance.confirm-tab-close")}:"))
confirmTabCloseBox.add(Box.createHorizontalStrut(8))
confirmTabCloseBox.add(confirmTabCloseComBoBox)
builder.add(confirmTabCloseBox).xyw(1, rows,3).apply { rows += step }
return builder.build() return builder.build()
} }

View File

@@ -1,5 +1,6 @@
package app.termora package app.termora
import app.termora.Database.Appearance
import app.termora.actions.DataProvider import app.termora.actions.DataProvider
import java.beans.PropertyChangeListener import java.beans.PropertyChangeListener
import javax.swing.Icon import javax.swing.Icon
@@ -44,10 +45,15 @@ interface TerminalTab : Disposable, DataProvider {
fun canClose(): Boolean = true fun canClose(): Boolean = true
/** /**
* 返回 true 表示可以关闭 * 返回 true 表示可以关闭,只有当 [Appearance.confirmTabClose] 为 false 时才会调用
*/ */
fun willBeClose(): Boolean = true fun willBeClose(): Boolean = true
/**
* 即将关闭,已经无法挽回
*/
fun beforeClose() {}
/** /**
* 是否可以克隆 * 是否可以克隆
*/ */

View File

@@ -32,6 +32,7 @@ class TerminalTabbed(
private val actionManager = ActionManager.getInstance() private val actionManager = ActionManager.getInstance()
private val dataProviderSupport = DataProviderSupport() private val dataProviderSupport = DataProviderSupport()
private val titleProperty = UUID.randomUUID().toSimpleString() private val titleProperty = UUID.randomUUID().toSimpleString()
private val appearance get() = Database.getDatabase().appearance
private val iconListener = PropertyChangeListener { e -> private val iconListener = PropertyChangeListener { e ->
val source = e.source val source = e.source
if (e.propertyName == "icon" && source is TerminalTab) { if (e.propertyName == "icon" && source is TerminalTab) {
@@ -153,8 +154,29 @@ class TerminalTabbed(
if (tabbedPane.isTabClosable(index)) { if (tabbedPane.isTabClosable(index)) {
val tab = tabs[index] val tab = tabs[index]
// 询问是否可以关闭
if (disposable) { if (disposable) {
if (!tab.willBeClose()) { // 如果开启了关闭确认,那么直接询问用户
if (appearance.confirmTabClose) {
if (OptionPane.showConfirmDialog(
windowScope.window,
I18n.getString("termora.tabbed.tab.close-prompt"),
messageType = JOptionPane.QUESTION_MESSAGE,
optionType = JOptionPane.OK_CANCEL_OPTION
) != JOptionPane.OK_OPTION
) {
return
}
} else if (!tab.willBeClose()) { // 如果没有开启则询问用户
return
}
}
// 通知即将关闭
if (disposable) {
try {
tab.beforeClose()
} catch (_: Exception) {
return return
} }
} }

View File

@@ -57,6 +57,7 @@ termora.settings.appearance.follow-system=Sync with OS
termora.settings.appearance.opacity=Opacity termora.settings.appearance.opacity=Opacity
termora.settings.appearance.background-image=BG Image termora.settings.appearance.background-image=BG Image
termora.settings.appearance.background-running=Backgrounding termora.settings.appearance.background-running=Backgrounding
termora.settings.appearance.confirm-tab-close=Confirm tab close
termora.setting.security=Security termora.setting.security=Security
termora.setting.security.enter-password=Enter password termora.setting.security.enter-password=Enter password
@@ -233,6 +234,7 @@ termora.tabbed.contextmenu.close-other-tabs=Close Other Tabs
termora.tabbed.contextmenu.close-all-tabs=Close All Tabs termora.tabbed.contextmenu.close-all-tabs=Close All Tabs
termora.tabbed.contextmenu.reconnect=Reconnect termora.tabbed.contextmenu.reconnect=Reconnect
termora.tabbed.local-tab.close-prompt=Do you want to terminal a running process in this terminal? termora.tabbed.local-tab.close-prompt=Do you want to terminal a running process in this terminal?
termora.tabbed.tab.close-prompt=Are you sure you want to close this tab?
# Terminal logger # Terminal logger
termora.terminal-logger=Terminal Logger termora.terminal-logger=Terminal Logger

View File

@@ -54,6 +54,7 @@ termora.settings.appearance.follow-system=跟随系统
termora.settings.appearance.opacity=透明度 termora.settings.appearance.opacity=透明度
termora.settings.appearance.background-image=背景图 termora.settings.appearance.background-image=背景图
termora.settings.appearance.background-running=后台运行 termora.settings.appearance.background-running=后台运行
termora.settings.appearance.confirm-tab-close=标签关闭前确认
termora.setting.security=安全 termora.setting.security=安全
termora.setting.security.enter-password=请输入密码 termora.setting.security.enter-password=请输入密码
@@ -222,6 +223,7 @@ termora.tabbed.contextmenu.close-other-tabs=关闭其他标签页
termora.tabbed.contextmenu.close-all-tabs=关闭所有标签页 termora.tabbed.contextmenu.close-all-tabs=关闭所有标签页
termora.tabbed.contextmenu.reconnect=重新连接 termora.tabbed.contextmenu.reconnect=重新连接
termora.tabbed.local-tab.close-prompt=你想要终止这个终端中正在运行的进程吗? termora.tabbed.local-tab.close-prompt=你想要终止这个终端中正在运行的进程吗?
termora.tabbed.tab.close-prompt=你确定要关闭这个标签页吗?
# Terminal logger # Terminal logger

View File

@@ -55,6 +55,7 @@ termora.settings.appearance.follow-system=跟隨系統
termora.settings.appearance.opacity=透明度 termora.settings.appearance.opacity=透明度
termora.settings.appearance.background-image=背景圖 termora.settings.appearance.background-image=背景圖
termora.settings.appearance.background-running=後台運行 termora.settings.appearance.background-running=後台運行
termora.settings.appearance.confirm-tab-close=關閉分頁確認
termora.setting.security=安全 termora.setting.security=安全
termora.setting.security.enter-password=請輸入密碼 termora.setting.security.enter-password=請輸入密碼
@@ -218,7 +219,7 @@ termora.tabbed.contextmenu.close-other-tabs=關閉其他標籤頁
termora.tabbed.contextmenu.close-all-tabs=關閉所有標籤 termora.tabbed.contextmenu.close-all-tabs=關閉所有標籤
termora.tabbed.contextmenu.reconnect=重新連接 termora.tabbed.contextmenu.reconnect=重新連接
termora.tabbed.local-tab.close-prompt=你想要終止這個終端機中正在運作的進程嗎? termora.tabbed.local-tab.close-prompt=你想要終止這個終端機中正在運作的進程嗎?
termora.tabbed.tab.close-prompt=你確定要關閉這個分頁嗎?
# Terminal logger # Terminal logger