diff --git a/src/main/kotlin/app/termora/Actions.kt b/src/main/kotlin/app/termora/Actions.kt index 2178cab..6ff3b85 100644 --- a/src/main/kotlin/app/termora/Actions.kt +++ b/src/main/kotlin/app/termora/Actions.kt @@ -20,7 +20,7 @@ object Actions { /** * 关键词高亮 */ - const val KEYWORD_HIGHLIGHT_EVERYWHERE = "KeywordHighlightAction" + const val KEYWORD_HIGHLIGHT = "KeywordHighlightAction" /** * Key manager diff --git a/src/main/kotlin/app/termora/CustomizeToolBarDialog.kt b/src/main/kotlin/app/termora/CustomizeToolBarDialog.kt new file mode 100644 index 0000000..e40159c --- /dev/null +++ b/src/main/kotlin/app/termora/CustomizeToolBarDialog.kt @@ -0,0 +1,351 @@ +package app.termora + +import app.termora.Application.ohMyJson +import app.termora.db.Database +import com.jgoodies.forms.builder.FormBuilder +import com.jgoodies.forms.layout.FormLayout +import kotlinx.serialization.encodeToString +import org.apache.commons.lang3.StringUtils +import org.jdesktop.swingx.action.ActionManager +import java.awt.Component +import java.awt.Dimension +import java.awt.Window +import java.awt.event.WindowAdapter +import java.awt.event.WindowEvent +import javax.swing.* +import javax.swing.event.ListDataEvent +import javax.swing.event.ListDataListener +import kotlin.math.max +import kotlin.math.min + +class CustomizeToolBarDialog( + owner: Window, + private val toolbar: TermoraToolBar +) : DialogWrapper(owner) { + + private val moveTopBtn = JButton(Icons.moveUp) + private val moveBottomBtn = JButton(Icons.moveDown) + private val upBtn = JButton(Icons.up) + private val downBtn = JButton(Icons.down) + + private val leftBtn = JButton(Icons.left) + private val rightBtn = JButton(Icons.right) + private val allToLeftBtn = JButton(Icons.applyNotConflictsRight) + private val allToRightBtn = JButton(Icons.applyNotConflictsLeft) + + private val leftList = ToolBarActionList() + private val rightList = ToolBarActionList() + private val actionManager get() = ActionManager.getInstance() + + private var isOk = false + + init { + size = Dimension(UIManager.getInt("Dialog.width") - 150, UIManager.getInt("Dialog.height") - 100) + isModal = true + controlsVisible = false + isResizable = false + title = I18n.getString("termora.toolbar.customize-toolbar") + setLocationRelativeTo(null) + + moveTopBtn.isEnabled = false + moveBottomBtn.isEnabled = false + downBtn.isEnabled = false + upBtn.isEnabled = false + + leftBtn.isEnabled = false + rightBtn.isEnabled = false + + initEvents() + + init() + } + + + override fun createCenterPanel(): JComponent { + + allToLeftBtn.isEnabled = !rightList.model.isEmpty + allToRightBtn.isEnabled = !leftList.model.isEmpty + + val box = JToolBar(JToolBar.VERTICAL) + box.add(Box.createVerticalStrut(leftList.fixedCellHeight)) + box.add(rightBtn) + box.add(leftBtn) + box.add(Box.createVerticalGlue()) + box.add(allToRightBtn) + box.add(allToLeftBtn) + box.add(Box.createVerticalStrut(leftList.fixedCellHeight)) + + val box2 = JToolBar(JToolBar.VERTICAL) + box2.add(Box.createVerticalStrut(leftList.fixedCellHeight)) + box2.add(moveTopBtn) + box2.add(upBtn) + box2.add(Box.createVerticalGlue()) + box2.add(downBtn) + box2.add(moveBottomBtn) + box2.add(Box.createVerticalStrut(leftList.fixedCellHeight)) + + + return FormBuilder.create().debug(false) + .border(BorderFactory.createMatteBorder(1, 0, 0, 0, DynamicColor.BorderColor)) + .layout(FormLayout("default:grow, pref, default:grow, pref", "fill:p:grow")) + .add(JScrollPane(leftList).apply { + border = BorderFactory.createMatteBorder(0, 0, 0, 1, DynamicColor.BorderColor) + }).xy(1, 1) + .add(box).xy(2, 1) + .add(JScrollPane(rightList).apply { + border = BorderFactory.createMatteBorder(0, 1, 0, 1, DynamicColor.BorderColor) + }).xy(3, 1) + .add(box2).xy(4, 1) + .build() + } + + private fun initEvents() { + + rightList.addListSelectionListener { resetMoveButtons() } + + leftList.addListSelectionListener { + val indices = leftList.selectedIndices + rightBtn.isEnabled = indices.isNotEmpty() + } + + leftList.model.addListDataListener(object : ListDataListener { + override fun intervalAdded(e: ListDataEvent) { + contentsChanged(e) + } + + override fun intervalRemoved(e: ListDataEvent) { + contentsChanged(e) + } + + override fun contentsChanged(e: ListDataEvent) { + allToLeftBtn.isEnabled = !rightList.model.isEmpty + allToRightBtn.isEnabled = !leftList.model.isEmpty + resetMoveButtons() + } + }) + + rightList.model.addListDataListener(object : ListDataListener { + override fun intervalAdded(e: ListDataEvent) { + contentsChanged(e) + } + + override fun intervalRemoved(e: ListDataEvent) { + contentsChanged(e) + } + + override fun contentsChanged(e: ListDataEvent) { + allToLeftBtn.isEnabled = !rightList.model.isEmpty + allToRightBtn.isEnabled = !leftList.model.isEmpty + resetMoveButtons() + } + }) + + // move first + moveTopBtn.addActionListener { + val indices = rightList.selectedIndices + rightList.clearSelection() + for (index in indices.indices) { + val ele = rightList.model.getElementAt(indices[index]) + rightList.model.removeElementAt(indices[index]) + rightList.model.add(index, ele) + rightList.selectionModel.addSelectionInterval(index, max(index - 1, 0)) + } + } + + // move up + upBtn.addActionListener { + val indices = rightList.selectedIndices + rightList.clearSelection() + for (index in indices) { + val ele = rightList.model.getElementAt(index) + rightList.model.removeElementAt(index) + rightList.model.add(index - 1, ele) + rightList.selectionModel.addSelectionInterval(max(index - 1, 0), max(index - 1, 0)) + } + } + + // move down + downBtn.addActionListener { + val indices = rightList.selectedIndices + rightList.clearSelection() + for (index in indices) { + val ele = rightList.model.getElementAt(index) + rightList.model.removeElementAt(index) + rightList.model.add(index + 1, ele) + rightList.selectionModel.addSelectionInterval(index + 1, index + 1) + } + } + + // move last + moveBottomBtn.addActionListener { + val indices = rightList.selectedIndices + val size = rightList.model.size + rightList.clearSelection() + for (index in indices.indices) { + val ele = rightList.model.getElementAt(indices[index]) + rightList.model.removeElementAt(indices[index]) + rightList.model.add(size - index - 1, ele) + rightList.selectionModel.addSelectionInterval(size - index - 1, size - index - 1) + } + } + + allToLeftBtn.addActionListener { + while (!rightList.model.isEmpty) { + val ele = rightList.model.getElementAt(0) + rightList.model.removeElementAt(0) + leftList.model.addElement(ele) + } + } + + allToRightBtn.addActionListener { + while (!leftList.model.isEmpty) { + val ele = leftList.model.getElementAt(0) + leftList.model.removeElementAt(0) + rightList.model.addElement(ele) + } + } + + leftBtn.addActionListener { + val indices = rightList.selectedIndices + for (index in indices) { + val ele = rightList.model.getElementAt(index) + rightList.model.removeElementAt(index) + leftList.model.addElement(ele) + } + rightList.clearSelection() + val index = min(indices.max(), rightList.model.size - 1) + if (!rightList.model.isEmpty) { + rightList.addSelectionInterval(index, index) + } + } + + rightBtn.addActionListener { + val indices = leftList.selectedIndices + val rightSelectedIndex = if (rightList.selectedIndices.isEmpty()) rightList.model.size else + rightList.selectionModel.maxSelectionIndex + 1 + + if (indices.isNotEmpty()) { + for (index in indices.indices) { + val ele = leftList.model.getElementAt(indices[index]) + leftList.model.removeElementAt(indices[index]) + rightList.model.add(rightSelectedIndex + index, ele) + } + + leftList.clearSelection() + val index = min(indices.max(), leftList.model.size - 1) + if (!leftList.model.isEmpty) { + leftList.addSelectionInterval(index, index) + } + + rightList.clearSelection() + rightList.addSelectionInterval(rightSelectedIndex, rightSelectedIndex) + } + } + + addWindowListener(object : WindowAdapter() { + override fun windowOpened(e: WindowEvent) { + removeWindowListener(this) + + val allActions = toolbar.getAllActions().toMutableList() + val shownActions = toolbar.getShownActions() + allActions.removeAll(shownActions) + for (action in allActions) { + actionManager.getAction(action)?.let { leftList.model.addElement(ActionHolder(action, it)) } + } + for (action in shownActions) { + actionManager.getAction(action)?.let { rightList.model.addElement(ActionHolder(action, it)) } + } + } + }) + } + + private fun resetMoveButtons() { + val indices = rightList.selectedIndices + if (indices.isEmpty()) { + moveTopBtn.isEnabled = false + moveBottomBtn.isEnabled = false + downBtn.isEnabled = false + upBtn.isEnabled = false + } else { + moveTopBtn.isEnabled = !indices.contains(0) + upBtn.isEnabled = moveTopBtn.isEnabled + moveBottomBtn.isEnabled = !indices.contains(rightList.model.size - 1) + downBtn.isEnabled = moveBottomBtn.isEnabled + } + leftBtn.isEnabled = indices.isNotEmpty() + } + + private class ToolBarActionList : JList() { + private val model = DefaultListModel() + + init { + initView() + initEvents() + setModel(model) + } + + private fun initView() { + border = BorderFactory.createEmptyBorder(4, 4, 4, 4) + background = UIManager.getColor("window") + fixedCellHeight = UIManager.getInt("Tree.rowHeight") + cellRenderer = object : DefaultListCellRenderer() { + override fun getListCellRendererComponent( + list: JList<*>?, + value: Any?, + index: Int, + isSelected: Boolean, + cellHasFocus: Boolean + ): Component { + var text = value?.toString() ?: StringUtils.EMPTY + if (value is ActionHolder) { + val action = value.action + text = action.getValue(Action.NAME)?.toString() ?: text + } + + val c = super.getListCellRendererComponent(list, text, index, isSelected, cellHasFocus) + if (value is ActionHolder) { + val action = value.action + val icon = action.getValue(Action.SMALL_ICON) as Icon? + if (icon != null) { + this.icon = icon + if (icon is DynamicIcon) { + if (isSelected && cellHasFocus) { + this.icon = icon.dark + } + } + } + } + + return c + } + } + + } + + private fun initEvents() { + + } + + override fun getModel(): DefaultListModel { + return model + } + } + + override fun doOKAction() { + isOk = true + val actions = mutableListOf() + for (i in 0 until rightList.model.size()) { + actions.add(rightList.model.getElementAt(i).id) + } + Database.instance.properties.putString("Termora.ToolBar.Actions", ohMyJson.encodeToString(actions)) + super.doOKAction() + } + + fun open(): Boolean { + isModal = true + isVisible = true + return isOk + } + + private class ActionHolder(val id: String, val action: Action) +} \ No newline at end of file diff --git a/src/main/kotlin/app/termora/Icons.kt b/src/main/kotlin/app/termora/Icons.kt index aa4e75c..599a1bb 100644 --- a/src/main/kotlin/app/termora/Icons.kt +++ b/src/main/kotlin/app/termora/Icons.kt @@ -3,7 +3,9 @@ package app.termora object Icons { val bulletList by lazy { DynamicIcon("icons/bulletList.svg", "icons/bulletList_dark.svg") } val up by lazy { DynamicIcon("icons/up.svg", "icons/up_dark.svg") } + val moveUp by lazy { DynamicIcon("icons/moveUp.svg", "icons/moveUp_dark.svg") } val down by lazy { DynamicIcon("icons/down.svg", "icons/down_dark.svg") } + val moveDown by lazy { DynamicIcon("icons/moveDown.svg", "icons/moveDown_dark.svg") } val close by lazy { DynamicIcon("icons/close.svg", "icons/close_dark.svg") } val searchHistory by lazy { DynamicIcon("icons/searchHistory.svg", "icons/searchHistory_dark.svg") } val matchCase by lazy { DynamicIcon("icons/matchCase.svg", "icons/matchCase_dark.svg") } @@ -74,9 +76,23 @@ object Icons { val colorPicker by lazy { DynamicIcon("icons/colorPicker.svg", "icons/colorPicker_dark.svg") } val folder by lazy { DynamicIcon("icons/folder.svg", "icons/folder_dark.svg") } val listFiles by lazy { DynamicIcon("icons/listFiles.svg", "icons/listFiles_dark.svg") } + val left by lazy { DynamicIcon("icons/left.svg", "icons/left_dark.svg") } + val right by lazy { DynamicIcon("icons/right.svg", "icons/right_dark.svg") } val dotListFiles by lazy { DynamicIcon("icons/dotListFiles.svg", "icons/dotListFiles_dark.svg") } val fileTransfer by lazy { DynamicIcon("icons/fileTransfer.svg", "icons/fileTransfer_dark.svg") } val help by lazy { DynamicIcon("icons/help.svg", "icons/help_dark.svg") } + val applyNotConflictsLeft by lazy { + DynamicIcon( + "icons/applyNotConflictsLeft.svg", + "icons/applyNotConflictsLeft_dark.svg" + ) + } + val applyNotConflictsRight by lazy { + DynamicIcon( + "icons/applyNotConflictsRight.svg", + "icons/applyNotConflictsRight_dark.svg" + ) + } val expand by lazy { DynamicIcon("icons/expand.svg", "icons/expand_dark.svg") } val collapse by lazy { DynamicIcon("icons/collapse.svg", "icons/collapse_dark.svg") } val expandAll by lazy { DynamicIcon("icons/expandAll.svg", "icons/expandAll_dark.svg") } diff --git a/src/main/kotlin/app/termora/TerminalTabbed.kt b/src/main/kotlin/app/termora/TerminalTabbed.kt index 289fff7..a836d11 100644 --- a/src/main/kotlin/app/termora/TerminalTabbed.kt +++ b/src/main/kotlin/app/termora/TerminalTabbed.kt @@ -7,27 +7,21 @@ import app.termora.findeverywhere.FindEverywhereResult import com.formdev.flatlaf.FlatLaf import com.formdev.flatlaf.extras.components.FlatPopupMenu import com.formdev.flatlaf.extras.components.FlatTabbedPane -import org.apache.commons.lang3.StringUtils -import org.jdesktop.swingx.action.ActionContainerFactory import org.jdesktop.swingx.action.ActionManager -import java.awt.BorderLayout -import java.awt.Component -import java.awt.Dimension -import java.awt.event.ActionEvent -import java.awt.event.KeyEvent -import java.awt.event.MouseAdapter -import java.awt.event.MouseEvent -import java.beans.PropertyChangeEvent +import java.awt.* +import java.awt.event.* import java.beans.PropertyChangeListener import javax.swing.* import javax.swing.JTabbedPane.SCROLL_TAB_LAYOUT import kotlin.math.min class TerminalTabbed( - private val toolbar: JToolBar, + private val termoraToolBar: TermoraToolBar, private val tabbedPane: FlatTabbedPane, ) : JPanel(BorderLayout()), Disposable, TerminalTabbedManager { private val tabs = mutableListOf() + private val customizeToolBarAWTEventListener = CustomizeToolBarAWTEventListener() + private val toolbar = termoraToolBar.getJToolBar() private val iconListener = PropertyChangeListener { e -> val source = e.source @@ -53,34 +47,6 @@ class TerminalTabbed( tabbedPane.styleMap = mapOf( "focusColor" to UIManager.getColor("TabbedPane.selectedBackground") ) - - val actionManager = ActionManager.getInstance() - val actionContainerFactory = ActionContainerFactory(actionManager) - val updateBtn = actionContainerFactory.createButton(actionManager.getAction(Actions.APP_UPDATE)) - updateBtn.isVisible = updateBtn.isEnabled - updateBtn.addChangeListener { updateBtn.isVisible = updateBtn.isEnabled } - - toolbar.add(actionContainerFactory.createButton(object : AnAction(StringUtils.EMPTY, Icons.add) { - override fun actionPerformed(e: ActionEvent?) { - actionManager.getAction(Actions.FIND_EVERYWHERE)?.actionPerformed(e) - } - - override fun isEnabled(): Boolean { - return actionManager.getAction(Actions.FIND_EVERYWHERE)?.isEnabled ?: false - } - })) - toolbar.add(Box.createHorizontalStrut(UIManager.getInt("TabbedPane.tabHeight"))) - toolbar.add(Box.createHorizontalGlue()) - toolbar.add(actionContainerFactory.createButton(actionManager.getAction(Actions.TERMINAL_LOGGER))) - toolbar.add(actionContainerFactory.createButton(actionManager.getAction(Actions.MACRO))) - toolbar.add(actionContainerFactory.createButton(actionManager.getAction(Actions.KEYWORD_HIGHLIGHT_EVERYWHERE))) - toolbar.add(actionContainerFactory.createButton(actionManager.getAction(Actions.KEY_MANAGER))) - toolbar.add(actionContainerFactory.createButton(actionManager.getAction(Actions.MULTIPLE))) - toolbar.add(updateBtn) - toolbar.add(actionContainerFactory.createButton(actionManager.getAction(Actions.FIND_EVERYWHERE))) - toolbar.add(actionContainerFactory.createButton(actionManager.getAction(Actions.SETTING))) - - tabbedPane.trailingComponent = toolbar add(tabbedPane, BorderLayout.CENTER) @@ -93,18 +59,16 @@ class TerminalTabbed( tabbedPane.setTabCloseCallback { _, i -> removeTabAt(i, true) } // 选中变动 - tabbedPane.addPropertyChangeListener("selectedIndex", object : PropertyChangeListener { - override fun propertyChange(evt: PropertyChangeEvent) { - val oldIndex = evt.oldValue as Int - val newIndex = evt.newValue as Int - if (oldIndex >= 0 && tabs.size > newIndex) { - tabs[oldIndex].onLostFocus() - } - if (newIndex >= 0 && tabs.size > newIndex) { - tabs[newIndex].onGrabFocus() - } + tabbedPane.addPropertyChangeListener("selectedIndex") { evt -> + val oldIndex = evt.oldValue as Int + val newIndex = evt.newValue as Int + if (oldIndex >= 0 && tabs.size > newIndex) { + tabs[oldIndex].onLostFocus() } - }) + if (newIndex >= 0 && tabs.size > newIndex) { + tabs[newIndex].onGrabFocus() + } + } // 选择变动 tabbedPane.addChangeListener { @@ -209,6 +173,9 @@ class TerminalTabbed( } }) + // 监听全局事件 + toolkit.addAWTEventListener(customizeToolBarAWTEventListener, AWTEvent.MOUSE_EVENT_MASK) + } private fun removeTabAt(index: Int, disposable: Boolean = true) { @@ -274,14 +241,10 @@ class TerminalTabbed( // 克隆 val clone = popupMenu.add(I18n.getString("termora.tabbed.contextmenu.clone")) clone.addActionListener { - val index = tabbedPane.selectedIndex - if (index > 0) { - val tab = tabs[index] - if (tab is HostTerminalTab) { - ActionManager.getInstance() - .getAction(Actions.OPEN_HOST) - .actionPerformed(OpenHostActionEvent(this, tab.host)) - } + if (tab is HostTerminalTab) { + ActionManager.getInstance() + .getAction(Actions.OPEN_HOST) + .actionPerformed(OpenHostActionEvent(this, tab.host)) } } @@ -370,6 +333,64 @@ class TerminalTabbed( Disposer.register(this, tab) } + /** + * 对着 ToolBar 右键 + */ + private inner class CustomizeToolBarAWTEventListener : AWTEventListener, Disposable { + init { + Disposer.register(this@TerminalTabbed, this) + } + + override fun eventDispatched(event: AWTEvent) { + if (event !is MouseEvent || event.id != MouseEvent.MOUSE_CLICKED || !SwingUtilities.isRightMouseButton(event)) return + // 如果 ToolBar 没有显示 + if (!toolbar.isShowing) return + // 如果不是作用于在 ToolBar 上面 + if (!Rectangle(toolbar.locationOnScreen, toolbar.size).contains(event.locationOnScreen)) return + + // 显示右键菜单 + showContextMenu(event) + } + + private fun showContextMenu(event: MouseEvent) { + val popupMenu = FlatPopupMenu() + popupMenu.add(I18n.getString("termora.toolbar.customize-toolbar")).addActionListener { + val dialog = CustomizeToolBarDialog( + SwingUtilities.getWindowAncestor(this@TerminalTabbed), + termoraToolBar + ) + if (dialog.open()) { + termoraToolBar.rebuild() + } + } + popupMenu.show(event.component, event.x, event.y) + } + + override fun dispose() { + toolkit.removeAWTEventListener(this) + } + } + + /*private inner class CustomizeToolBarDialog(owner: Window) : DialogWrapper(owner) { + init { + size = Dimension(UIManager.getInt("Dialog.width"), UIManager.getInt("Dialog.height")) + isModal = true + title = I18n.getString("termora.setting") + setLocationRelativeTo(null) + + init() + } + + override fun createCenterPanel(): JComponent { + val model = DefaultListModel() + val checkBoxList = CheckBoxList(model) + checkBoxList.fixedCellHeight = UIManager.getInt("Tree.rowHeight") + model.addElement("Test") + return checkBoxList + } + + }*/ + private inner class SwitchFindEverywhereResult( private val title: String, private val icon: Icon?, diff --git a/src/main/kotlin/app/termora/TermoraFrame.kt b/src/main/kotlin/app/termora/TermoraFrame.kt index 9340ba5..3987e0a 100644 --- a/src/main/kotlin/app/termora/TermoraFrame.kt +++ b/src/main/kotlin/app/termora/TermoraFrame.kt @@ -44,12 +44,12 @@ class TermoraFrame : JFrame() { private val log = LoggerFactory.getLogger(TermoraFrame::class.java) } - private val toolbar = JToolBar() + private val titleBar = LogicCustomTitleBar.createCustomTitleBar(this) private val tabbedPane = MyTabbedPane() + private val toolbar = TermoraToolBar(titleBar, tabbedPane) private lateinit var terminalTabbed: TerminalTabbed private val disposable = Disposer.newDisposable() private val isWindowDecorationsSupported by lazy { JBR.isWindowDecorationsSupported() } - private val titleBar = LogicCustomTitleBar.createCustomTitleBar(this) private val updaterManager get() = UpdaterManager.instance private val preferencesHandler = object : Runnable { @@ -81,38 +81,6 @@ class TermoraFrame : JFrame() { private fun initEvents() { - // 监听窗口大小变动,然后修改边距避开控制按钮 - addComponentListener(object : ComponentAdapter() { - override fun componentResized(e: ComponentEvent) { - 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() - - for (i in 0 until toolbar.componentCount) { - val c = toolbar.getComponent(i) - if (c.name == "spacing") { - if (c.width == right) { - return - } - toolbar.remove(i) - break - } - } - - if (right > 0) { - val spacing = Box.createHorizontalStrut(right) - spacing.name = "spacing" - toolbar.add(spacing) - } - } - } - }) - forceHitTest() // macos 需要判断是否全部删除 @@ -210,7 +178,7 @@ class TermoraFrame : JFrame() { // Keyword Highlight - ActionManager.getInstance().addAction(Actions.KEYWORD_HIGHLIGHT_EVERYWHERE, object : AnAction( + ActionManager.getInstance().addAction(Actions.KEYWORD_HIGHLIGHT, object : AnAction( I18n.getString("termora.highlight"), Icons.edit ) { @@ -444,8 +412,8 @@ class TermoraFrame : JFrame() { tabbedPane.addMouseListener(mouseAdapter) tabbedPane.addMouseMotionListener(mouseAdapter) - toolbar.addMouseListener(mouseAdapter) - toolbar.addMouseMotionListener(mouseAdapter) + toolbar.getJToolBar().addMouseListener(mouseAdapter) + toolbar.getJToolBar().addMouseMotionListener(mouseAdapter) } private fun initDesktopHandler() { diff --git a/src/main/kotlin/app/termora/TermoraToolBar.kt b/src/main/kotlin/app/termora/TermoraToolBar.kt new file mode 100644 index 0000000..06f6953 --- /dev/null +++ b/src/main/kotlin/app/termora/TermoraToolBar.kt @@ -0,0 +1,141 @@ +package app.termora + +import app.termora.Application.ohMyJson +import app.termora.db.Database +import com.formdev.flatlaf.extras.components.FlatTabbedPane +import com.formdev.flatlaf.util.SystemInfo +import com.jetbrains.WindowDecorations +import org.apache.commons.lang3.StringUtils +import org.jdesktop.swingx.action.ActionContainerFactory +import org.jdesktop.swingx.action.ActionManager +import java.awt.Insets +import java.awt.event.ActionEvent +import java.awt.event.ComponentAdapter +import java.awt.event.ComponentEvent +import javax.swing.Box +import javax.swing.JToolBar + +class TermoraToolBar( + private val titleBar: WindowDecorations.CustomTitleBar, + private val tabbedPane: FlatTabbedPane +) { + private val properties by lazy { Database.instance.properties } + private val toolbar by lazy { MyToolBar().apply { rebuild(this) } } + + private val shownActions = mutableListOf() + + fun getJToolBar(): JToolBar { + return toolbar + } + + + fun getShownActions(): List { + return shownActions + } + + fun getAllActions(): List { + return listOf( + Actions.TERMINAL_LOGGER, + Actions.MACRO, + Actions.KEYWORD_HIGHLIGHT, + Actions.KEY_MANAGER, + Actions.MULTIPLE, + Actions.FIND_EVERYWHERE, + Actions.SETTING, + ) + } + + fun rebuild() { + rebuild(this.toolbar) + } + + private fun rebuild(toolbar: JToolBar) { + val actionManager = ActionManager.getInstance() + val actionContainerFactory = ActionContainerFactory(actionManager) + + shownActions.clear() + toolbar.removeAll() + + toolbar.add(actionContainerFactory.createButton(object : AnAction(StringUtils.EMPTY, Icons.add) { + override fun actionPerformed(e: ActionEvent?) { + actionManager.getAction(Actions.FIND_EVERYWHERE)?.actionPerformed(e) + } + + override fun isEnabled(): Boolean { + return actionManager.getAction(Actions.FIND_EVERYWHERE)?.isEnabled ?: false + } + })) + + toolbar.add(Box.createHorizontalGlue()) + + val actions = ohMyJson.runCatching { + ohMyJson.decodeFromString>( + properties.getString( + "Termora.ToolBar.Actions", + StringUtils.EMPTY + ) + ) + }.getOrNull() ?: getAllActions() + + + // update btn + val updateBtn = actionContainerFactory.createButton(actionManager.getAction(Actions.APP_UPDATE)) + updateBtn.isVisible = updateBtn.isEnabled + updateBtn.addChangeListener { updateBtn.isVisible = updateBtn.isEnabled } + toolbar.add(updateBtn) + + for (action in actions) { + actionManager.getAction(action)?.let { + toolbar.add(actionContainerFactory.createButton(it)) + shownActions.add(action) + } + } + + if (toolbar is MyToolBar) { + toolbar.adjust() + } + + toolbar.revalidate() + toolbar.repaint() + } + + private inner class MyToolBar : JToolBar() { + init { + // 监听窗口大小变动,然后修改边距避开控制按钮 + addComponentListener(object : ComponentAdapter() { + override fun componentResized(e: ComponentEvent) { + adjust() + } + }) + } + + 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() + val toolbar = this@MyToolBar + for (i in 0 until toolbar.componentCount) { + val c = toolbar.getComponent(i) + if (c.name == "spacing") { + if (c.width == right) { + return + } + toolbar.remove(i) + break + } + } + + if (right > 0) { + val spacing = Box.createHorizontalStrut(right) + spacing.name = "spacing" + toolbar.add(spacing) + } + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/termora/findeverywhere/QuickActionsFindEverywhereProvider.kt b/src/main/kotlin/app/termora/findeverywhere/QuickActionsFindEverywhereProvider.kt index 14808bf..ad98daf 100644 --- a/src/main/kotlin/app/termora/findeverywhere/QuickActionsFindEverywhereProvider.kt +++ b/src/main/kotlin/app/termora/findeverywhere/QuickActionsFindEverywhereProvider.kt @@ -5,7 +5,12 @@ import app.termora.I18n import org.jdesktop.swingx.action.ActionManager class QuickActionsFindEverywhereProvider : FindEverywhereProvider { - private val actions = listOf(Actions.KEY_MANAGER, Actions.KEYWORD_HIGHLIGHT_EVERYWHERE, Actions.MULTIPLE) + private val actions = listOf( + Actions.KEY_MANAGER, + Actions.KEYWORD_HIGHLIGHT, + Actions.MULTIPLE, + ) + override fun find(pattern: String): List { val actionManager = ActionManager.getInstance() return actions diff --git a/src/main/resources/i18n/messages.properties b/src/main/resources/i18n/messages.properties index 8c26b2b..8bdc2ca 100644 --- a/src/main/resources/i18n/messages.properties +++ b/src/main/resources/i18n/messages.properties @@ -268,7 +268,8 @@ termora.transport.jobs.table.estimated-time=Estimated time termora.transport.jobs.contextmenu.delete=${termora.remove} termora.transport.jobs.contextmenu.delete-all=Delete All - +# ToolBar +termora.toolbar.customize-toolbar=Customize Toolbar... # Terminal termora.terminal.size=Size: {0} x {1} diff --git a/src/main/resources/i18n/messages_zh_CN.properties b/src/main/resources/i18n/messages_zh_CN.properties index 75137b0..e6b42d2 100644 --- a/src/main/resources/i18n/messages_zh_CN.properties +++ b/src/main/resources/i18n/messages_zh_CN.properties @@ -260,6 +260,8 @@ termora.transport.jobs.table.speed=速度 termora.transport.jobs.table.estimated-time=剩余时间 termora.transport.jobs.contextmenu.delete-all=删除所有 +# ToolBar +termora.toolbar.customize-toolbar=自定义工具栏... termora.terminal.size=大小: {0} x {1} termora.terminal.copied=已复制 diff --git a/src/main/resources/i18n/messages_zh_TW.properties b/src/main/resources/i18n/messages_zh_TW.properties index cd97c71..7b8d803 100644 --- a/src/main/resources/i18n/messages_zh_TW.properties +++ b/src/main/resources/i18n/messages_zh_TW.properties @@ -240,6 +240,8 @@ termora.transport.jobs.table.speed=速度 termora.transport.jobs.table.estimated-time=剩餘時間 termora.transport.jobs.contextmenu.delete-all=刪除所有 +# ToolBar +termora.toolbar.customize-toolbar=自訂工具列... termora.terminal.size=大小: {0} x {1} termora.terminal.copied=已複製 diff --git a/src/main/resources/icons/applyNotConflictsLeft.svg b/src/main/resources/icons/applyNotConflictsLeft.svg new file mode 100644 index 0000000..043d53e --- /dev/null +++ b/src/main/resources/icons/applyNotConflictsLeft.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/main/resources/icons/applyNotConflictsLeft_dark.svg b/src/main/resources/icons/applyNotConflictsLeft_dark.svg new file mode 100644 index 0000000..89266d3 --- /dev/null +++ b/src/main/resources/icons/applyNotConflictsLeft_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/main/resources/icons/applyNotConflictsRight.svg b/src/main/resources/icons/applyNotConflictsRight.svg new file mode 100644 index 0000000..0561f0a --- /dev/null +++ b/src/main/resources/icons/applyNotConflictsRight.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/main/resources/icons/applyNotConflictsRight_dark.svg b/src/main/resources/icons/applyNotConflictsRight_dark.svg new file mode 100644 index 0000000..202ab54 --- /dev/null +++ b/src/main/resources/icons/applyNotConflictsRight_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/main/resources/icons/left.svg b/src/main/resources/icons/left.svg new file mode 100644 index 0000000..5088005 --- /dev/null +++ b/src/main/resources/icons/left.svg @@ -0,0 +1,6 @@ + + + + diff --git a/src/main/resources/icons/left_dark.svg b/src/main/resources/icons/left_dark.svg new file mode 100644 index 0000000..e8dd9cb --- /dev/null +++ b/src/main/resources/icons/left_dark.svg @@ -0,0 +1,6 @@ + + + + diff --git a/src/main/resources/icons/moveDown.svg b/src/main/resources/icons/moveDown.svg new file mode 100644 index 0000000..298e777 --- /dev/null +++ b/src/main/resources/icons/moveDown.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/src/main/resources/icons/moveDown_dark.svg b/src/main/resources/icons/moveDown_dark.svg new file mode 100644 index 0000000..a310901 --- /dev/null +++ b/src/main/resources/icons/moveDown_dark.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/src/main/resources/icons/moveUp.svg b/src/main/resources/icons/moveUp.svg new file mode 100644 index 0000000..c9fe9cb --- /dev/null +++ b/src/main/resources/icons/moveUp.svg @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/src/main/resources/icons/moveUp_dark.svg b/src/main/resources/icons/moveUp_dark.svg new file mode 100644 index 0000000..de13a40 --- /dev/null +++ b/src/main/resources/icons/moveUp_dark.svg @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/src/main/resources/icons/right.svg b/src/main/resources/icons/right.svg new file mode 100644 index 0000000..ebab26b --- /dev/null +++ b/src/main/resources/icons/right.svg @@ -0,0 +1,6 @@ + + + + diff --git a/src/main/resources/icons/right_dark.svg b/src/main/resources/icons/right_dark.svg new file mode 100644 index 0000000..fdcff72 --- /dev/null +++ b/src/main/resources/icons/right_dark.svg @@ -0,0 +1,6 @@ + + + +