Coverage for graphica/gui/shell/project_tabs.py: 94.3%
64 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-12 16:38 +0000
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-12 16:38 +0000
1"""プロジェクトのタブ。タブの帯は上部バーに置き、中身(各タブの PlotterApp)はその下に重ねる。
3QTabWidget は帯と中身を1つの部品に持つので、帯だけを上部バーへ移せない。今まで QTabWidget で使っていた呼び方
4(addTab・removeTab・widget・indexOf・count・currentIndex・tabText など)はそのまま使える。
5"""
6from PySide6.QtCore import Qt, Signal
7from PySide6.QtWidgets import QStackedWidget, QTabBar, QVBoxLayout, QWidget
10class ProjectTabs(QWidget):
11 currentChanged = Signal(int)
12 tabCloseRequested = Signal(int)
14 def __init__(self, parent=None):
15 super().__init__(parent)
16 self._bar = QTabBar()
17 self._bar.setObjectName("project_tab_bar")
18 self._bar.setDrawBase(False)
19 self._bar.setExpanding(False)
20 self._bar.setElideMode(Qt.TextElideMode.ElideRight)
21 self._bar.setUsesScrollButtons(True)
22 self._bar.setFocusPolicy(Qt.FocusPolicy.NoFocus)
23 self._stack = QStackedWidget(self)
24 layout = QVBoxLayout(self)
25 layout.setContentsMargins(0, 0, 0, 0)
26 layout.addWidget(self._stack)
27 self._bar.currentChanged.connect(self._on_bar_current_changed)
28 self._bar.tabCloseRequested.connect(self.tabCloseRequested)
29 self._bar.tabMoved.connect(self._on_tab_moved)
31 def tabBar(self):
32 return self._bar
34 def _on_bar_current_changed(self, index):
35 if 0 <= index < self._stack.count(): 35 ↛ 37line 35 didn't jump to line 37 because the condition on line 35 was always true
36 self._stack.setCurrentIndex(index)
37 self.currentChanged.emit(index)
39 def _on_tab_moved(self, from_index, to_index):
40 widget = self._stack.widget(from_index)
41 self._stack.removeWidget(widget)
42 self._stack.insertWidget(to_index, widget)
43 self._stack.setCurrentIndex(self._bar.currentIndex())
45 def addTab(self, widget, text):
46 # 先に中身を足す(帯に足した時点で currentChanged が出て、その先が中身を引く)
47 self._stack.addWidget(widget)
48 return self._bar.addTab(text)
50 def removeTab(self, index):
51 if not 0 <= index < self._stack.count(): 51 ↛ 52line 51 didn't jump to line 52 because the condition on line 51 was never true
52 return
53 self._stack.removeWidget(self._stack.widget(index))
54 self._bar.removeTab(index)
56 def widget(self, index):
57 return self._stack.widget(index)
59 def indexOf(self, widget):
60 return self._stack.indexOf(widget)
62 def count(self):
63 return self._bar.count()
65 def currentIndex(self):
66 return self._bar.currentIndex()
68 def setCurrentIndex(self, index):
69 self._bar.setCurrentIndex(index)
71 def currentWidget(self):
72 return self._stack.currentWidget()
74 def setCurrentWidget(self, widget):
75 index = self.indexOf(widget)
76 if index >= 0: 76 ↛ exitline 76 didn't return from function 'setCurrentWidget' because the condition on line 76 was always true
77 self.setCurrentIndex(index)
79 def tabText(self, index):
80 return self._bar.tabText(index)
82 def setTabText(self, index, text):
83 self._bar.setTabText(index, text)
85 def setTabsClosable(self, closable):
86 self._bar.setTabsClosable(closable)
88 def setMovable(self, movable):
89 self._bar.setMovable(movable)