diff options
Diffstat (limited to 'qutebrowser/mainwindow/tabbedbrowser.py')
-rw-r--r-- | qutebrowser/mainwindow/tabbedbrowser.py | 79 |
1 files changed, 56 insertions, 23 deletions
diff --git a/qutebrowser/mainwindow/tabbedbrowser.py b/qutebrowser/mainwindow/tabbedbrowser.py index a96f6d583..840e69cd0 100644 --- a/qutebrowser/mainwindow/tabbedbrowser.py +++ b/qutebrowser/mainwindow/tabbedbrowser.py @@ -28,7 +28,7 @@ from typing import ( Any, Deque, List, Mapping, MutableMapping, MutableSequence, Optional, Tuple) from PyQt5.QtWidgets import QSizePolicy, QWidget, QApplication -from PyQt5.QtCore import pyqtSignal, pyqtSlot, QTimer, QUrl +from PyQt5.QtCore import pyqtSignal, pyqtSlot, QTimer, QUrl, QPoint from qutebrowser.config import config from qutebrowser.keyinput import modeman @@ -73,14 +73,14 @@ class TabDeque: size = config.val.tabs.focus_stack_size if size < 0: size = None - self._stack: Deque[weakref.ReferenceType[QWidget]] = collections.deque( - maxlen=size) + self._stack: Deque[weakref.ReferenceType[browsertab.AbstractTab]] = ( + collections.deque(maxlen=size)) # Items that have been removed from the primary stack. - self._stack_deleted: List[weakref.ReferenceType[QWidget]] = [] + self._stack_deleted: List[weakref.ReferenceType[browsertab.AbstractTab]] = [] self._ignore_next = False self._keep_deleted_next = False - def on_switch(self, old_tab: QWidget) -> None: + def on_switch(self, old_tab: browsertab.AbstractTab) -> None: """Record tab switch events.""" if self._ignore_next: self._ignore_next = False @@ -92,24 +92,29 @@ class TabDeque: self._keep_deleted_next = False self._stack.append(tab) - def prev(self, cur_tab: QWidget) -> QWidget: + def prev(self, cur_tab: browsertab.AbstractTab) -> browsertab.AbstractTab: """Get the 'previous' tab in the stack. Throws IndexError on failure. """ - tab: Optional[QWidget] = None + tab: Optional[browsertab.AbstractTab] = None while tab is None or tab.pending_removal or tab is cur_tab: tab = self._stack.pop()() self._stack_deleted.append(weakref.ref(cur_tab)) self._ignore_next = True return tab - def next(self, cur_tab: QWidget, *, keep_overflow: bool = True) -> QWidget: + def next( + self, + cur_tab: browsertab.AbstractTab, + *, + keep_overflow: bool = True, + ) -> browsertab.AbstractTab: """Get the 'next' tab in the stack. Throws IndexError on failure. """ - tab: Optional[QWidget] = None + tab: Optional[browsertab.AbstractTab] = None while tab is None or tab.pending_removal or tab is cur_tab: tab = self._stack_deleted.pop()() # On next tab-switch, current tab will be added to stack as normal. @@ -118,7 +123,7 @@ class TabDeque: self._keep_deleted_next = True return tab - def last(self, cur_tab: QWidget) -> QWidget: + def last(self, cur_tab: browsertab.AbstractTab) -> browsertab.AbstractTab: """Get the last tab. Throws IndexError on failure. @@ -216,7 +221,11 @@ class TabbedBrowser(QWidget): self.widget.tabCloseRequested.connect(self.on_tab_close_requested) self.widget.new_tab_requested.connect(self.tabopen) self.widget.currentChanged.connect(self._on_current_changed) - self.cur_fullscreen_requested.connect(self.widget.tabBar().maybe_hide) + + tabbar = self.widget.tabBar() + assert isinstance(tabbar, tabwidget.TabBar) + self.cur_fullscreen_requested.connect(tabbar.maybe_hide) + self.widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) # load_finished instead of load_started as WORKAROUND for @@ -235,8 +244,8 @@ class TabbedBrowser(QWidget): self._now_focused = None self.search_text = None self.search_options: Mapping[str, Any] = {} - self._local_marks: MutableMapping[QUrl, MutableMapping[str, int]] = {} - self._global_marks: MutableMapping[str, Tuple[int, QUrl]] = {} + self._local_marks: MutableMapping[QUrl, MutableMapping[str, QPoint]] = {} + self._global_marks: MutableMapping[str, Tuple[QPoint, QUrl]] = {} self.default_window_icon = self.widget.window().windowIcon() self.is_private = private self.tab_deque = TabDeque() @@ -373,6 +382,25 @@ class TabbedBrowser(QWidget): tab.history_item_triggered.connect( history.web_history.add_from_tab) + def _current_tab(self) -> browsertab.AbstractTab: + """Get the current browser tab. + + Note: The assert ensures the current tab is never None. + """ + tab = self.widget.currentWidget() + assert isinstance(tab, browsertab.AbstractTab), tab + return tab + + def _tab_by_idx(self, idx: int) -> Optional[browsertab.AbstractTab]: + """Get a browser tab by index. + + If no tab was found at the given index, None is returned. + """ + tab = self.widget.widget(idx) + if tab is not None: + assert isinstance(tab, browsertab.AbstractTab), tab + return tab + def current_url(self): """Get the URL of the current tab. @@ -503,13 +531,15 @@ class TabbedBrowser(QWidget): ] only_one_tab_open = self.widget.count() == 1 if only_one_tab_open and last_close_replaces: - no_history = len(self.widget.widget(0).history) == 1 + tab = self._tab_by_idx(0) + assert tab is not None + no_history = len(tab.history) == 1 urls = { 'blank': QUrl('about:blank'), 'startpage': config.val.url.start_pages[0], 'default-page': config.val.url.default_page, } - first_tab_url = self.widget.widget(0).url() + first_tab_url = tab.url() last_close_urlstr = urls[last_close].toString().rstrip('/') first_tab_urlstr = first_tab_url.toString().rstrip('/') last_close_url_used = first_tab_urlstr == last_close_urlstr @@ -520,7 +550,8 @@ class TabbedBrowser(QWidget): for entry in reversed(entries): if use_current_tab: - newtab = self.widget.widget(0) + newtab = self._tab_by_idx(0) + assert newtab is not None use_current_tab = False else: newtab = self.tabopen(background=False, idx=entry.index) @@ -540,14 +571,14 @@ class TabbedBrowser(QWidget): if newtab or self.widget.currentWidget() is None: self.tabopen(url, background=False) else: - self.widget.currentWidget().load_url(url) + self._current_tab().load_url(url) @pyqtSlot(int) def on_tab_close_requested(self, idx): """Close a tab via an index.""" - tab = self.widget.widget(idx) + tab = self._tab_by_idx(idx) if tab is None: - log.webview.debug( # type: ignore[unreachable] + log.webview.debug( "Got invalid tab {} for index {}!".format(tab, idx)) return self.tab_close_prompt_if_pinned( @@ -820,6 +851,7 @@ class TabbedBrowser(QWidget): mode in modeman.INPUT_MODES): tab = self.widget.currentWidget() if tab is not None: + assert isinstance(tab, browsertab.AbstractTab) tab.data.input_mode = mode @pyqtSlot(usertypes.KeyMode) @@ -833,6 +865,7 @@ class TabbedBrowser(QWidget): widget)) widget.setFocus() if config.val.tabs.mode_on_change == 'restore': + assert isinstance(widget, browsertab.AbstractTab) widget.data.input_mode = usertypes.KeyMode.normal @pyqtSlot(int) @@ -842,9 +875,9 @@ class TabbedBrowser(QWidget): if idx == -1 or self.is_shutting_down: # closing the last tab (before quitting) or shutting down return - tab = self.widget.widget(idx) + tab = self._tab_by_idx(idx) if tab is None: - log.webview.debug( # type: ignore[unreachable] + log.webview.debug( "on_current_changed got called with invalid index {}" .format(idx)) return @@ -1022,7 +1055,7 @@ class TabbedBrowser(QWidget): if key != "'": message.error("Failed to set mark: url invalid") return - point = self.widget.currentWidget().scroller.pos_px() + point = self._current_tab().scroller.pos_px() if key.isupper(): self._global_marks[key] = point, url @@ -1043,7 +1076,7 @@ class TabbedBrowser(QWidget): except qtutils.QtValueError: urlkey = None - tab = self.widget.currentWidget() + tab = self._current_tab() if key.isupper(): if key in self._global_marks: |