diff --git a/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionTabsComp.java b/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionTabsComp.java index b19484370..dc034324f 100644 --- a/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionTabsComp.java +++ b/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionTabsComp.java @@ -4,13 +4,16 @@ import atlantafx.base.controls.RingProgressIndicator; import atlantafx.base.theme.Styles; import io.xpipe.app.browser.BrowserWelcomeComp; import io.xpipe.app.comp.base.MultiContentComp; +import io.xpipe.app.core.AppI18n; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.impl.PrettyImageHelper; import io.xpipe.app.fxcomps.impl.TooltipAugment; +import io.xpipe.app.fxcomps.util.LabelGraphic; import io.xpipe.app.fxcomps.util.PlatformThread; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.util.BooleanScope; +import io.xpipe.app.util.ContextMenuHelper; import io.xpipe.app.util.InputHelper; import javafx.application.Platform; import javafx.beans.binding.Bindings; @@ -21,9 +24,7 @@ import javafx.beans.value.ObservableValue; import javafx.collections.ListChangeListener; import javafx.geometry.Insets; import javafx.geometry.Pos; -import javafx.scene.control.Label; -import javafx.scene.control.Tab; -import javafx.scene.control.TabPane; +import javafx.scene.control.*; import javafx.scene.input.DragEvent; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; @@ -31,10 +32,7 @@ import javafx.scene.input.KeyCombination; import javafx.scene.layout.Region; import javafx.scene.layout.StackPane; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.UUID; +import java.util.*; import static atlantafx.base.theme.Styles.DENSE; import static atlantafx.base.theme.Styles.toggleStyleClass; @@ -247,8 +245,65 @@ public class BrowserSessionTabsComp extends SimpleComp { return tabs; } + private ContextMenu createContextMenu(TabPane tabs, Tab tab) { + var cm = ContextMenuHelper.create(); + + var select = ContextMenuHelper.item(LabelGraphic.none(), AppI18n.get("selectTab")); + select.acceleratorProperty().bind(Bindings.createObjectBinding(() -> { + var start = KeyCode.F1.getCode(); + var index = tabs.getTabs().indexOf(tab); + var keyCode = Arrays.stream(KeyCode.values()).filter(code -> code.getCode() == start + index).findAny().orElse(null); + return keyCode != null ? new KeyCodeCombination(keyCode) : null; + }, tabs.getTabs())); + cm.getItems().add(select); + + cm.getItems().add(new SeparatorMenuItem()); + + var close = ContextMenuHelper.item(LabelGraphic.none(), AppI18n.get("closeTab" )); + close.setAccelerator(new KeyCodeCombination(KeyCode.W, KeyCombination.SHORTCUT_DOWN)); + close.setOnAction(event -> { + tabs.getTabs().remove(tab); + event.consume(); + }); + cm.getItems().add(close); + + var closeOthers = ContextMenuHelper.item(LabelGraphic.none(), AppI18n.get("closeOtherTabs")); + closeOthers.setOnAction(event -> { + tabs.getTabs().removeAll(tabs.getTabs().stream().filter(t -> t != tab).toList()); + event.consume(); + }); + cm.getItems().add(closeOthers); + + var closeLeft = ContextMenuHelper.item(LabelGraphic.none(), AppI18n.get("closeLeftTabs")); + closeLeft.setOnAction(event -> { + var index = tabs.getTabs().indexOf(tab); + tabs.getTabs().removeAll(tabs.getTabs().stream().filter(t -> tabs.getTabs().indexOf(t) < index).toList()); + event.consume(); + }); + cm.getItems().add(closeLeft); + + var closeRight = ContextMenuHelper.item(LabelGraphic.none(), AppI18n.get("closeRightTabs")); + closeRight.setOnAction(event -> { + var index = tabs.getTabs().indexOf(tab); + tabs.getTabs().removeAll(tabs.getTabs().stream().filter(t -> tabs.getTabs().indexOf(t) > index).toList()); + event.consume(); + }); + cm.getItems().add(closeRight); + + var closeAll = ContextMenuHelper.item(LabelGraphic.none(), AppI18n.get("closeAllTabs")); + closeAll.setAccelerator(new KeyCodeCombination(KeyCode.W, KeyCombination.SHORTCUT_DOWN, KeyCombination.SHIFT_DOWN)); + closeAll.setOnAction(event -> { + tabs.getTabs().clear(); + event.consume(); + }); + cm.getItems().add(closeAll); + + return cm; + } + private Tab createTab(TabPane tabs, BrowserSessionTab model) { var tab = new Tab(); + tab.setContextMenu(createContextMenu(tabs, tab)); var ring = new RingProgressIndicator(0, false); ring.setMinSize(16, 16); diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreQuickAccessButtonComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreQuickAccessButtonComp.java index 57d39e0ef..db170476f 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreQuickAccessButtonComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreQuickAccessButtonComp.java @@ -4,6 +4,7 @@ import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.CompStructure; import io.xpipe.app.fxcomps.impl.IconButtonComp; import io.xpipe.app.fxcomps.impl.PrettyImageHelper; +import io.xpipe.app.fxcomps.util.LabelGraphic; import io.xpipe.app.util.ContextMenuHelper; import javafx.geometry.Side; @@ -44,7 +45,7 @@ public class StoreQuickAccessButtonComp extends Comp> { w.getEntry().getProvider().getDisplayIconFileName(w.getEntry().getStore()); if (c.getList().isEmpty()) { var item = ContextMenuHelper.item( - PrettyImageHelper.ofFixedSizeSquare(graphic, 16), + new LabelGraphic.ImageGraphic(graphic, 16), w.getName().getValue()); item.setOnAction(event -> { action.accept(w); diff --git a/app/src/main/java/io/xpipe/app/fxcomps/util/LabelGraphic.java b/app/src/main/java/io/xpipe/app/fxcomps/util/LabelGraphic.java index c16e46484..071bd49f1 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/util/LabelGraphic.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/util/LabelGraphic.java @@ -1,19 +1,22 @@ package io.xpipe.app.fxcomps.util; import io.xpipe.app.fxcomps.Comp; - -import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.value.ObservableValue; +import io.xpipe.app.fxcomps.impl.PrettyImageHelper; import javafx.scene.Node; - import lombok.EqualsAndHashCode; import lombok.Value; import org.kordamp.ikonli.javafx.FontIcon; public abstract class LabelGraphic { - public static ObservableValue fixedIcon(String icon) { - return new SimpleObjectProperty<>(new IconGraphic(icon)); + public static LabelGraphic none() { + return new LabelGraphic() { + + @Override + public Node createGraphicNode() { + return null; + } + }; } public abstract Node createGraphicNode(); @@ -30,6 +33,20 @@ public abstract class LabelGraphic { } } + + @Value + @EqualsAndHashCode(callSuper = true) + public static class ImageGraphic extends LabelGraphic { + + String file; + int size; + + @Override + public Node createGraphicNode() { + return PrettyImageHelper.ofFixedSizeSquare(file, size).createRegion(); + } + } + @Value @EqualsAndHashCode(callSuper = true) public static class CompGraphic extends LabelGraphic { diff --git a/app/src/main/java/io/xpipe/app/util/ContextMenuHelper.java b/app/src/main/java/io/xpipe/app/util/ContextMenuHelper.java index aad686d37..e3d997fe4 100644 --- a/app/src/main/java/io/xpipe/app/util/ContextMenuHelper.java +++ b/app/src/main/java/io/xpipe/app/util/ContextMenuHelper.java @@ -1,7 +1,6 @@ package io.xpipe.app.util; -import io.xpipe.app.fxcomps.Comp; - +import io.xpipe.app.fxcomps.util.LabelGraphic; import javafx.application.Platform; import javafx.geometry.Side; import javafx.scene.Node; @@ -36,14 +35,14 @@ public class ContextMenuHelper { return contextMenu; } - public static MenuItem item(Comp graphic, String name) { - var i = new MenuItem(name, graphic.createRegion()); + public static MenuItem item(LabelGraphic graphic, String name) { + var i = new MenuItem(name, graphic.createGraphicNode()); return i; } public static void toggleShow(ContextMenu contextMenu, Node ref, Side side) { if (!contextMenu.isShowing()) { - contextMenu.show(ref, Side.RIGHT, 0, 0); + contextMenu.show(ref, side, 0, 0); } else { contextMenu.hide(); } diff --git a/lang/app/strings/translations_da.properties b/lang/app/strings/translations_da.properties index 29b3d05f7..d4cb76372 100644 --- a/lang/app/strings/translations_da.properties +++ b/lang/app/strings/translations_da.properties @@ -481,3 +481,9 @@ copyId=Kopi ID requireDoubleClickForConnections=Kræver dobbeltklik for forbindelser requireDoubleClickForConnectionsDescription=Hvis den er aktiveret, skal du dobbeltklikke på forbindelser for at starte dem. Det er nyttigt, hvis man er vant til at dobbeltklikke på ting. clearTransferDescription=Ryd valg +selectTab=Vælg fane +closeTab=Luk fanen +closeOtherTabs=Luk andre faner +closeAllTabs=Luk alle faner +closeLeftTabs=Luk faner til venstre +closeRightTabs=Luk faner til højre diff --git a/lang/app/strings/translations_de.properties b/lang/app/strings/translations_de.properties index 2cbd38e3b..2019dc886 100644 --- a/lang/app/strings/translations_de.properties +++ b/lang/app/strings/translations_de.properties @@ -475,3 +475,9 @@ copyId=ID kopieren requireDoubleClickForConnections=Doppelklick für Verbindungen erforderlich requireDoubleClickForConnectionsDescription=Wenn diese Funktion aktiviert ist, musst du auf die Verbindungen doppelklicken, um sie zu starten. Das ist nützlich, wenn du es gewohnt bist, auf Dinge doppelt zu klicken. clearTransferDescription=Auswahl löschen +selectTab=Registerkarte auswählen +closeTab=Registerkarte schließen +closeOtherTabs=Andere Tabs schließen +closeAllTabs=Alle Registerkarten schließen +closeLeftTabs=Tabs nach links schließen +closeRightTabs=Tabs nach rechts schließen diff --git a/lang/app/strings/translations_en.properties b/lang/app/strings/translations_en.properties index 6c15f5395..fbeacc82d 100644 --- a/lang/app/strings/translations_en.properties +++ b/lang/app/strings/translations_en.properties @@ -480,3 +480,9 @@ copyId=Copy ID requireDoubleClickForConnections=Require double click for connections requireDoubleClickForConnectionsDescription=If enabled, you have to double-click connections to launch them. This is useful if you're used to double-clicking things. clearTransferDescription=Clear selection +selectTab=Select tab +closeTab=Close tab +closeOtherTabs=Close other tabs +closeAllTabs=Close all tabs +closeLeftTabs=Close tabs to the left +closeRightTabs=Close tabs to the right diff --git a/lang/app/strings/translations_es.properties b/lang/app/strings/translations_es.properties index cf9a45f31..05a89cfdf 100644 --- a/lang/app/strings/translations_es.properties +++ b/lang/app/strings/translations_es.properties @@ -462,3 +462,9 @@ copyId=ID de copia requireDoubleClickForConnections=Requiere doble clic para las conexiones requireDoubleClickForConnectionsDescription=Si está activado, tienes que hacer doble clic en las conexiones para iniciarlas. Esto es útil si estás acostumbrado a hacer doble clic en las cosas. clearTransferDescription=Borrar selección +selectTab=Seleccionar pestaña +closeTab=Cerrar pestaña +closeOtherTabs=Cerrar otras pestañas +closeAllTabs=Cerrar todas las pestañas +closeLeftTabs=Cerrar pestañas a la izquierda +closeRightTabs=Cerrar pestañas a la derecha diff --git a/lang/app/strings/translations_fr.properties b/lang/app/strings/translations_fr.properties index 1d75f20d0..72c86b9cb 100644 --- a/lang/app/strings/translations_fr.properties +++ b/lang/app/strings/translations_fr.properties @@ -462,3 +462,9 @@ copyId=ID de copie requireDoubleClickForConnections=Nécessite un double clic pour les connexions requireDoubleClickForConnectionsDescription=Si cette option est activée, tu dois double-cliquer sur les connexions pour les lancer. C'est utile si tu as l'habitude de double-cliquer sur les choses. clearTransferDescription=Effacer la sélection +selectTab=Onglet de sélection +closeTab=Fermer l'onglet +closeOtherTabs=Fermer d'autres onglets +closeAllTabs=Fermer tous les onglets +closeLeftTabs=Ferme les onglets à gauche +closeRightTabs=Ferme les onglets à droite diff --git a/lang/app/strings/translations_it.properties b/lang/app/strings/translations_it.properties index 94212063c..2f3b6e1f7 100644 --- a/lang/app/strings/translations_it.properties +++ b/lang/app/strings/translations_it.properties @@ -462,3 +462,9 @@ copyId=Copia ID requireDoubleClickForConnections=Richiede un doppio clic per le connessioni requireDoubleClickForConnectionsDescription=Se abilitato, devi fare doppio clic sulle connessioni per avviarle. Questo è utile se sei abituato a fare doppio clic. clearTransferDescription=Cancella la selezione +selectTab=Seleziona scheda +closeTab=Chiudi scheda +closeOtherTabs=Chiudere altre schede +closeAllTabs=Chiudi tutte le schede +closeLeftTabs=Chiudere le schede a sinistra +closeRightTabs=Chiudere le schede a destra diff --git a/lang/app/strings/translations_ja.properties b/lang/app/strings/translations_ja.properties index 75e23cdbc..35d1c3641 100644 --- a/lang/app/strings/translations_ja.properties +++ b/lang/app/strings/translations_ja.properties @@ -462,3 +462,9 @@ copyId=コピーID requireDoubleClickForConnections=接続にはダブルクリックが必要 requireDoubleClickForConnectionsDescription=有効にすると、接続をダブルクリックしないと起動しなくなる。ダブルクリックに慣れている人には便利な機能だ。 clearTransferDescription=選択範囲をクリアする +selectTab=タブを選択する +closeTab=閉じるタブ +closeOtherTabs=他のタブを閉じる +closeAllTabs=すべてのタブを閉じる +closeLeftTabs=タブを左に閉じる +closeRightTabs=タブを右に閉じる diff --git a/lang/app/strings/translations_nl.properties b/lang/app/strings/translations_nl.properties index 350d3a941..e89be1216 100644 --- a/lang/app/strings/translations_nl.properties +++ b/lang/app/strings/translations_nl.properties @@ -462,3 +462,9 @@ copyId=ID kopiëren requireDoubleClickForConnections=Dubbelklikken vereist voor verbindingen requireDoubleClickForConnectionsDescription=Als dit is ingeschakeld, moet je dubbelklikken op verbindingen om ze te starten. Dit is handig als je gewend bent om op dingen te dubbelklikken. clearTransferDescription=Selectie wissen +selectTab=Tabblad selecteren +closeTab=Tabblad sluiten +closeOtherTabs=Andere tabbladen sluiten +closeAllTabs=Alle tabbladen sluiten +closeLeftTabs=Tabbladen naar links sluiten +closeRightTabs=Tabbladen naar rechts sluiten diff --git a/lang/app/strings/translations_pt.properties b/lang/app/strings/translations_pt.properties index c642a1874..af58d6df3 100644 --- a/lang/app/strings/translations_pt.properties +++ b/lang/app/strings/translations_pt.properties @@ -462,3 +462,9 @@ copyId=ID de cópia requireDoubleClickForConnections=Exige duplo clique para ligações requireDoubleClickForConnectionsDescription=Se estiver ativado, tens de fazer duplo clique nas ligações para as iniciar. Isto é útil se estiveres habituado a fazer duplo clique em coisas. clearTransferDescription=Limpar seleção +selectTab=Selecionar separador +closeTab=Fecha o separador +closeOtherTabs=Fecha outros separadores +closeAllTabs=Fecha todos os separadores +closeLeftTabs=Fecha os separadores à esquerda +closeRightTabs=Fecha os separadores à direita diff --git a/lang/app/strings/translations_ru.properties b/lang/app/strings/translations_ru.properties index 738d83e95..3a78fc083 100644 --- a/lang/app/strings/translations_ru.properties +++ b/lang/app/strings/translations_ru.properties @@ -462,3 +462,9 @@ copyId=Идентификатор копии requireDoubleClickForConnections=Требуется двойной щелчок для подключения requireDoubleClickForConnectionsDescription=Если эта опция включена, тебе придется дважды щелкнуть по соединениям, чтобы запустить их. Это полезно, если ты привык все запускать двойным щелчком. clearTransferDescription=Четкий выбор +selectTab=Выберите вкладку +closeTab=Закройте вкладку +closeOtherTabs=Закрыть другие вкладки +closeAllTabs=Закрыть все вкладки +closeLeftTabs=Закрыть вкладки слева +closeRightTabs=Закрывать вкладки справа diff --git a/lang/app/strings/translations_tr.properties b/lang/app/strings/translations_tr.properties index 67c1c6116..6624765dd 100644 --- a/lang/app/strings/translations_tr.properties +++ b/lang/app/strings/translations_tr.properties @@ -463,3 +463,9 @@ copyId=Kopya Kimliği requireDoubleClickForConnections=Bağlantılar için çift tıklama gerektir requireDoubleClickForConnectionsDescription=Etkinleştirilirse, bağlantıları başlatmak için çift tıklamanız gerekir. Bu, bir şeyleri çift tıklamaya alışkınsanız kullanışlıdır. clearTransferDescription=Seçimi temizle +selectTab=Sekme seçin +closeTab=Sekmeyi kapat +closeOtherTabs=Diğer sekmeleri kapatın +closeAllTabs=Tüm sekmeleri kapat +closeLeftTabs=Sekmeleri sola doğru kapatın +closeRightTabs=Sekmeleri sağa doğru kapatın diff --git a/lang/app/strings/translations_zh.properties b/lang/app/strings/translations_zh.properties index c97aa15c4..b267b44dc 100644 --- a/lang/app/strings/translations_zh.properties +++ b/lang/app/strings/translations_zh.properties @@ -462,3 +462,9 @@ copyId=复制 ID requireDoubleClickForConnections=要求双击连接 requireDoubleClickForConnectionsDescription=如果启用,则必须双击连接才能启动。如果您习惯双击事物,这将非常有用。 clearTransferDescription=清除选择 +selectTab=选择选项卡 +closeTab=关闭选项卡 +closeOtherTabs=关闭其他标签页 +closeAllTabs=关闭所有标签页 +closeLeftTabs=向左关闭标签 +closeRightTabs=向右关闭标签页