Files
elmprodvpn/selective-vpn-gui/main_window/singbox/runtime_cards_mixin.py

137 lines
5.8 KiB
Python

from __future__ import annotations
from PySide6.QtCore import Qt
from PySide6.QtWidgets import QMenu, QMessageBox
class SingBoxRuntimeCardsMixin:
def on_singbox_profile_card_context_menu(self, pos) -> None:
item = self.lst_singbox_profile_cards.itemAt(pos)
if item is None:
return
cid = str(item.data(Qt.UserRole) or "").strip()
if not cid:
return
menu = QMenu(self)
act_run = menu.addAction("Run")
act_edit = menu.addAction("Edit")
act_delete = menu.addAction("Delete")
chosen = menu.exec(self.lst_singbox_profile_cards.viewport().mapToGlobal(pos))
if chosen is None:
return
if not self._select_transport_engine_by_id(cid):
QMessageBox.warning(self, "SingBox profile", f"Profile '{cid}' is no longer available.")
return
if chosen == act_run:
self.on_transport_engine_action("start")
return
if chosen == act_edit:
self.on_singbox_profile_edit_dialog(cid)
return
if chosen == act_delete:
self.on_transport_engine_delete(cid)
return
def on_singbox_profile_card_selected(self) -> None:
if self._syncing_singbox_selection:
return
items = self.lst_singbox_profile_cards.selectedItems()
if not items:
return
cid = str(items[0].data(Qt.UserRole) or "").strip()
if not cid:
return
idx = self.cmb_transport_engine.findData(cid)
if idx < 0:
return
if idx != self.cmb_transport_engine.currentIndex():
self._syncing_singbox_selection = True
try:
self.cmb_transport_engine.setCurrentIndex(idx)
finally:
self._syncing_singbox_selection = False
return
self._refresh_singbox_profile_card_styles()
self._sync_selected_singbox_profile_link(silent=True)
self._load_singbox_editor_for_selected(silent=True)
self._update_transport_engine_view()
def _singbox_value_label(self, key: str, value: str) -> str:
v = str(value or "").strip().lower()
if key == "routing":
if v == "full":
return "Full tunnel"
return "Selective"
if key == "dns":
if v == "singbox_dns":
return "SingBox DNS"
return "System resolver"
if key == "killswitch":
if v == "off":
return "Disabled"
return "Enabled"
return v or ""
def _effective_singbox_policy(self) -> tuple[str, str, str]:
route = str(self.cmb_singbox_global_routing.currentData() or "selective").strip().lower()
dns = str(self.cmb_singbox_global_dns.currentData() or "system_resolver").strip().lower()
killswitch = str(self.cmb_singbox_global_killswitch.currentData() or "on").strip().lower()
if not self.chk_singbox_profile_use_global_routing.isChecked():
route = str(self.cmb_singbox_profile_routing.currentData() or route).strip().lower()
if route == "global":
route = str(self.cmb_singbox_global_routing.currentData() or "selective").strip().lower()
if not self.chk_singbox_profile_use_global_dns.isChecked():
dns = str(self.cmb_singbox_profile_dns.currentData() or dns).strip().lower()
if dns == "global":
dns = str(self.cmb_singbox_global_dns.currentData() or "system_resolver").strip().lower()
if not self.chk_singbox_profile_use_global_killswitch.isChecked():
killswitch = str(self.cmb_singbox_profile_killswitch.currentData() or killswitch).strip().lower()
if killswitch == "global":
killswitch = str(self.cmb_singbox_global_killswitch.currentData() or "on").strip().lower()
return route, dns, killswitch
def _refresh_singbox_profile_effective(self) -> None:
route, dns, killswitch = self._effective_singbox_policy()
route_txt = self._singbox_value_label("routing", route)
dns_txt = self._singbox_value_label("dns", dns)
kill_txt = self._singbox_value_label("killswitch", killswitch)
self.lbl_singbox_profile_effective.setText(
f"Effective: routing={route_txt} | dns={dns_txt} | kill-switch={kill_txt}"
)
self.lbl_singbox_profile_effective.setStyleSheet("color: gray;")
def _apply_singbox_profile_controls(self) -> None:
self.cmb_singbox_profile_routing.setEnabled(
not self.chk_singbox_profile_use_global_routing.isChecked()
)
self.cmb_singbox_profile_dns.setEnabled(
not self.chk_singbox_profile_use_global_dns.isChecked()
)
self.cmb_singbox_profile_killswitch.setEnabled(
not self.chk_singbox_profile_use_global_killswitch.isChecked()
)
self._refresh_singbox_profile_effective()
def _apply_singbox_compact_visibility(self) -> None:
show_profile = bool(self.btn_singbox_toggle_profile_settings.isChecked())
self.grp_singbox_profile_settings.setVisible(show_profile)
self.btn_singbox_toggle_profile_settings.setText(
"Hide profile settings" if show_profile else "Profile settings"
)
show_global = bool(self.btn_singbox_toggle_global_defaults.isChecked())
self.grp_singbox_global_defaults.setVisible(show_global)
self.btn_singbox_toggle_global_defaults.setText(
"Hide global defaults" if show_global else "Global defaults"
)
show_log = bool(self.btn_singbox_toggle_activity.isChecked())
self.grp_singbox_activity.setVisible(show_log)
self.btn_singbox_toggle_activity.setText(
"Hide activity log" if show_log else "Activity log"
)