Layouts : 1 (normal), 2 verticaux (cote a cote), 2 horizontaux (empiles), 4 panneaux (grille 2x2), via des QSplitter imbriques (app/ui/split_pane.py). Chaque panneau reutilise tel quel un widget d'onglet existant (SessionTabWidget, LocalTerminalTabWidget) : aucune modification de ces classes, seule une fine barre (menu ☰ + fermeture) les enveloppe. - Menu contextuel d'un onglet (SSH ou terminal local, pas SFTP, pas d'imbrication de splits) : "Diviser" -> choix du layout. Le contenu actuel occupe le premier panneau, les autres recoivent un terminal local par defaut. - Menu ☰ d'un panneau : changer son contenu (autre terminal local), ou "Deplacer un onglet ici" pour y faire migrer un onglet de premier niveau existant sans fermer sa connexion. - Fermer un panneau le retire de son QSplitter (qui redistribue l'espace tout seul) ; s'il n'en reste qu'un, l'onglet redevient un onglet normal (redescente automatique, pas de chrome de split residuel). - Fermer l'onglet divise (bouton x) ferme toutes les connexions des panneaux. - BroadcastManager (Multi-Send) atteint desormais aussi les panneaux a l'interieur d'un split (MainWindow._iter_tabs les deplie). Bug intercepte par les tests avant integration : reparenter le widget d'origine dans son panneau retire automatiquement son onglet du QTabWidget (un widget ne peut avoir qu'un seul parent), ce qui decale les onglets suivants ; un appel explicite a removeTab() ensuite visait donc le mauvais onglet. Corrige en laissant Qt gerer ce retrait implicitement plutot que de le dupliquer. tests/test_split_terminal.py : SSHConnection.start()/LocalTerminalConnection.start() neutralisees (teste l'agencement des panneaux et le cycle de vie des onglets, pas une connexion reelle). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
4.6 KiB
4.6 KiB