161 lines
6.9 KiB
Markdown
161 lines
6.9 KiB
Markdown
# Отключить автоподключение терминала при одинарном клике
|
||
|
||
## Контекст
|
||
|
||
При одинарном клике на сервер в sidebar все табы (terminal, files, powershell) сразу подключаются к серверу. Пользователь хочет просто переключаться между серверами без автоподключения. Подключение — только по двойному клику.
|
||
|
||
## Подход
|
||
|
||
- **Одинарный клик** — выбрать сервер, обновить табы (info, setup, keys и т.д.), но НЕ подключаться к terminal/files/powershell
|
||
- **Двойной клик** — выбрать сервер + подключить все "connecting" табы (terminal, files, powershell)
|
||
- **Контекстное меню** "Open Terminal" / "Browse Files" — тоже подключает
|
||
|
||
Tkinter при двойном клике генерирует оба события: `<Button-1>` (первый клик) → `<Double-Button-1>`. Это нам на руку: первый клик выберет сервер, двойной клик — подключит. Debounce не нужен.
|
||
|
||
## Изменения — 4 файла
|
||
|
||
### 1. `gui/sidebar.py` — добавить двойной клик
|
||
|
||
**Строка 37** — добавить `on_double_click` в конструктор:
|
||
```python
|
||
def __init__(self, master, store, on_select=None, on_double_click=None, session_pool=None):
|
||
...
|
||
self.on_select = on_select
|
||
self.on_double_click = on_double_click
|
||
```
|
||
|
||
**Строки 272-275** — добавить `<Double-Button-1>` binding:
|
||
```python
|
||
for widget in [frame, info, name_label, detail_label, badge, type_badge, session_ind]:
|
||
widget.bind("<Button-1>", lambda e, a=alias: self._select(a))
|
||
widget.bind("<Double-Button-1>", lambda e, a=alias: self._on_double_click(a))
|
||
widget.bind("<Button-3>", lambda e, a=alias: self._show_context_menu(e, a))
|
||
```
|
||
|
||
**После `_select()`** (строка 372) — новый метод:
|
||
```python
|
||
def _on_double_click(self, alias: str):
|
||
self._select(alias)
|
||
if self.on_double_click:
|
||
self.on_double_click(alias)
|
||
```
|
||
|
||
### 2. `gui/tabs/terminal_tab.py` — убрать автоподключение
|
||
|
||
**Строки 49-67** — `set_server()`: заменить `self._connect()` на показ статуса:
|
||
```python
|
||
def set_server(self, alias: str | None):
|
||
if alias == self._current_alias:
|
||
return
|
||
if self._current_alias and self._session and self.session_pool:
|
||
buf = self._terminal.get_current_buffer()
|
||
self.session_pool.store_shell_state(self._current_alias, buf)
|
||
self._disconnect()
|
||
self._current_alias = alias
|
||
if alias:
|
||
self._terminal.set_status(t("term_click_to_connect").format(alias=alias), "#f59e0b")
|
||
else:
|
||
self._terminal.reset()
|
||
self._terminal.set_status(t("term_disconnected"), "#888888")
|
||
```
|
||
|
||
**Добавить публичный метод `connect()`** после `set_server()`:
|
||
```python
|
||
def connect(self):
|
||
"""Explicitly connect (double-click or context menu)."""
|
||
if self._current_alias and not self._session:
|
||
self._connect()
|
||
```
|
||
|
||
### 3. `gui/tabs/files_tab.py` — убрать автоподключение
|
||
|
||
**Строки 304-311** — `set_server()`: заменить `self._connect_sftp()` на статус:
|
||
```python
|
||
if alias:
|
||
if self.session_pool:
|
||
stored_path, stored_sudo = self.session_pool.get_sftp_state(alias)
|
||
if stored_path != "/":
|
||
self._remote_path = stored_path
|
||
self._remote_status.configure(text=t("sftp_click_to_connect"))
|
||
else:
|
||
...
|
||
```
|
||
|
||
**Добавить публичный метод `connect()`**:
|
||
```python
|
||
def connect(self):
|
||
"""Explicitly connect SFTP (double-click or context menu)."""
|
||
if self._current_alias and not self._sftp:
|
||
self._connect_sftp()
|
||
```
|
||
|
||
### 4. `gui/tabs/powershell_tab.py` — убрать автоподключение
|
||
|
||
**Строка 100** — заменить `self._connect(alias)` на статус:
|
||
```python
|
||
if alias is None:
|
||
self._set_status(t("ps_disconnected"), "#888888")
|
||
return
|
||
self._set_status(t("term_click_to_connect").format(alias=alias), "#f59e0b")
|
||
```
|
||
|
||
**Добавить публичный метод `connect()`**:
|
||
```python
|
||
def connect(self):
|
||
"""Explicitly connect WinRM (double-click or context menu)."""
|
||
if self._current_alias and not self._client:
|
||
self._connect(self._current_alias)
|
||
```
|
||
|
||
### 5. `gui/app.py` — подключить двойной клик
|
||
|
||
**Строка 157** — передать `on_double_click`:
|
||
```python
|
||
self.sidebar = Sidebar(self._paned, self.store,
|
||
on_select=self._on_server_select,
|
||
on_double_click=self._on_server_connect,
|
||
session_pool=self.session_pool)
|
||
```
|
||
|
||
**Новый метод `_on_server_connect()`** (после `_on_server_select`):
|
||
```python
|
||
def _on_server_connect(self, alias: str):
|
||
"""Double-click: connect interactive tabs (terminal, files, powershell)."""
|
||
for key, widget in self._tab_instances.items():
|
||
if hasattr(widget, "connect"):
|
||
widget.connect()
|
||
```
|
||
|
||
**Строки 350-358** — `_context_open_tab()`: добавить вызов `connect()`:
|
||
```python
|
||
def _context_open_tab(self, alias: str, tab_key: str):
|
||
self._on_server_select(alias)
|
||
self.sidebar._select(alias)
|
||
if tab_key in self._tab_keys:
|
||
try:
|
||
self.tabview.set(_tab_label(tab_key))
|
||
except Exception:
|
||
pass
|
||
# Connect the target tab if it supports explicit connection
|
||
widget = self._tab_instances.get(tab_key)
|
||
if widget and hasattr(widget, "connect"):
|
||
widget.connect()
|
||
```
|
||
|
||
### 6. `core/i18n.py` — 2 ключа перевода
|
||
|
||
Рядом с `term_disconnected`:
|
||
|
||
| Ключ | EN | RU | ZH |
|
||
|------|----|----|-----|
|
||
| `term_click_to_connect` | `Double-click to connect to {alias}` | `Двойной клик для подключения к {alias}` | `双击连接 {alias}` |
|
||
| `sftp_click_to_connect` | `Double-click server to browse files` | `Двойной клик для просмотра файлов` | `双击服务器浏览文件` |
|
||
|
||
## Верификация
|
||
|
||
1. `python build.py` — собрать exe
|
||
2. Запустить exe, одинарный клик на SSH-сервер → терминал показывает "Двойной клик для подключения", файлы показывают аналогичное сообщение, info таб работает как раньше
|
||
3. Двойной клик на сервер → терминал и файлы подключаются
|
||
4. Правый клик → "Open Terminal" → терминал подключается
|
||
5. Переключение между серверами одним кликом → нет автоподключений, быстрое переключение
|