diff options
Diffstat (limited to 'qutebrowser/mainwindow')
-rw-r--r-- | qutebrowser/mainwindow/mainwindow.py | 10 | ||||
-rw-r--r-- | qutebrowser/mainwindow/prompt.py | 4 | ||||
-rw-r--r-- | qutebrowser/mainwindow/statusbar/bar.py | 5 | ||||
-rw-r--r-- | qutebrowser/mainwindow/statusbar/command.py | 3 | ||||
-rw-r--r-- | qutebrowser/mainwindow/statusbar/url.py | 3 | ||||
-rw-r--r-- | qutebrowser/mainwindow/tabbedbrowser.py | 79 | ||||
-rw-r--r-- | qutebrowser/mainwindow/tabwidget.py | 73 |
7 files changed, 110 insertions, 67 deletions
diff --git a/qutebrowser/mainwindow/mainwindow.py b/qutebrowser/mainwindow/mainwindow.py index 7f62c2dc4..74522a091 100644 --- a/qutebrowser/mainwindow/mainwindow.py +++ b/qutebrowser/mainwindow/mainwindow.py @@ -92,7 +92,7 @@ def raise_window(window, alert=True): window.setWindowState(window.windowState() | Qt.WindowActive) window.raise_() # WORKAROUND for https://bugreports.qt.io/browse/QTBUG-69568 - QCoreApplication.processEvents( # type: ignore[call-overload] + QCoreApplication.processEvents( QEventLoop.ExcludeUserInputEvents | QEventLoop.ExcludeSocketNotifiers) if not sip.isdeleted(window): @@ -561,11 +561,11 @@ class MainWindow(QWidget): def _set_decoration(self, hidden): """Set the visibility of the window decoration via Qt.""" - window_flags: int = Qt.Window + window_flags = cast(Qt.WindowFlags, Qt.Window) refresh_window = self.isVisible() if hidden: window_flags |= Qt.CustomizeWindowHint | Qt.NoDropShadowWindowHint - self.setWindowFlags(cast(Qt.WindowFlags, window_flags)) + self.setWindowFlags(window_flags) if refresh_window: self.show() @@ -574,9 +574,7 @@ class MainWindow(QWidget): if not config.val.content.fullscreen.window: if on: self.state_before_fullscreen = self.windowState() - self.setWindowState( - Qt.WindowFullScreen | # type: ignore[arg-type] - self.state_before_fullscreen) # type: ignore[operator] + self.setWindowState(Qt.WindowFullScreen | self.state_before_fullscreen) elif self.isFullScreen(): self.setWindowState(self.state_before_fullscreen) log.misc.debug('on: {}, state before fullscreen: {}'.format( diff --git a/qutebrowser/mainwindow/prompt.py b/qutebrowser/mainwindow/prompt.py index 6fea16093..f7a04bee0 100644 --- a/qutebrowser/mainwindow/prompt.py +++ b/qutebrowser/mainwindow/prompt.py @@ -784,7 +784,7 @@ class FilenamePrompt(_BasePrompt): selmodel.setCurrentIndex( idx, - QItemSelectionModel.ClearAndSelect | # type: ignore[arg-type] + QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows) self._insert_path(idx, clicked=False) @@ -808,7 +808,7 @@ class DownloadFilenamePrompt(FilenamePrompt): def __init__(self, question, parent=None): super().__init__(question, parent) self._file_model.setFilter( - QDir.AllDirs | QDir.Drives | QDir.NoDotAndDotDot) # type: ignore[arg-type] + QDir.AllDirs | QDir.Drives | QDir.NoDotAndDotDot) def accept(self, value=None, save=False): done = super().accept(value, save) diff --git a/qutebrowser/mainwindow/statusbar/bar.py b/qutebrowser/mainwindow/statusbar/bar.py index 8bad290be..46cf083bd 100644 --- a/qutebrowser/mainwindow/statusbar/bar.py +++ b/qutebrowser/mainwindow/statusbar/bar.py @@ -22,8 +22,7 @@ import enum import dataclasses -from PyQt5.QtCore import (pyqtSignal, pyqtSlot, # type: ignore[attr-defined] - pyqtProperty, Qt, QSize, QTimer) +from PyQt5.QtCore import pyqtSignal, pyqtSlot, pyqtProperty, Qt, QSize, QTimer from PyQt5.QtWidgets import QWidget, QHBoxLayout, QStackedLayout, QSizePolicy from qutebrowser.browser import browsertab @@ -300,7 +299,7 @@ class StatusBar(QWidget): padding = config.val.statusbar.padding self._hbox.setContentsMargins(padding.left, 0, padding.right, 0) - @pyqtProperty('QStringList') + @pyqtProperty('QStringList') # type: ignore[type-var] def color_flags(self): """Getter for self.color_flags, so it can be used as Qt property.""" return self._color_flags.to_stringlist() diff --git a/qutebrowser/mainwindow/statusbar/command.py b/qutebrowser/mainwindow/statusbar/command.py index 199f0a103..95076380a 100644 --- a/qutebrowser/mainwindow/statusbar/command.py +++ b/qutebrowser/mainwindow/statusbar/command.py @@ -19,6 +19,7 @@ """The commandline in the statusbar.""" +from typing import Optional from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QSize from PyQt5.QtGui import QKeyEvent @@ -240,7 +241,7 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit): self.clear_completion_selection.emit() self.hide_completion.emit() - def setText(self, text: str) -> None: + def setText(self, text: Optional[str]) -> None: """Extend setText to set prefix and make sure the prompt is ok.""" if not text: pass diff --git a/qutebrowser/mainwindow/statusbar/url.py b/qutebrowser/mainwindow/statusbar/url.py index 99818e284..ca9b15779 100644 --- a/qutebrowser/mainwindow/statusbar/url.py +++ b/qutebrowser/mainwindow/statusbar/url.py @@ -21,8 +21,7 @@ import enum -from PyQt5.QtCore import (pyqtSlot, pyqtProperty, # type: ignore[attr-defined] - QUrl) +from PyQt5.QtCore import pyqtSlot, pyqtProperty, QUrl from qutebrowser.mainwindow.statusbar import textbase from qutebrowser.config import stylesheet 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: diff --git a/qutebrowser/mainwindow/tabwidget.py b/qutebrowser/mainwindow/tabwidget.py index 511c2c309..2239b5ad3 100644 --- a/qutebrowser/mainwindow/tabwidget.py +++ b/qutebrowser/mainwindow/tabwidget.py @@ -22,7 +22,7 @@ import functools import contextlib import dataclasses -from typing import Optional, cast +from typing import Optional, Dict, Any from PyQt5.QtCore import (pyqtSignal, pyqtSlot, Qt, QSize, QRect, QPoint, QTimer, QUrl) @@ -76,17 +76,30 @@ class TabWidget(QTabWidget): @config.change_filter('tabs') def _init_config(self): """Initialize attributes based on the config.""" - tabbar = self.tabBar() self.setMovable(True) self.setTabsClosable(False) position = config.val.tabs.position selection_behavior = config.val.tabs.select_on_remove self.setTabPosition(position) - tabbar.vertical = position in [ # type: ignore[attr-defined] - QTabWidget.West, QTabWidget.East] + + tabbar = self._tab_bar() + tabbar.vertical = position in [QTabWidget.West, QTabWidget.East] tabbar.setSelectionBehaviorOnRemove(selection_behavior) tabbar.refresh() + def _tab_bar(self) -> "TabBar": + """Get the TabBar for this TabWidget.""" + bar = self.tabBar() + assert isinstance(bar, TabBar) + return bar + + def _tab_by_idx(self, idx: int) -> Optional[browsertab.AbstractTab]: + """Get the tab at the given index.""" + tab = self.widget(idx) + if tab is not None: + assert isinstance(tab, browsertab.AbstractTab) + return tab + def set_tab_indicator_color(self, idx, color): """Set the tab indicator color. @@ -94,17 +107,17 @@ class TabWidget(QTabWidget): idx: The tab index. color: A QColor. """ - bar = self.tabBar() + bar = self._tab_bar() bar.set_tab_data(idx, 'indicator-color', color) bar.update(bar.tabRect(idx)) def tab_indicator_color(self, idx): """Get the tab indicator color for the given index.""" - return self.tabBar().tab_indicator_color(idx) + return self._tab_bar().tab_indicator_color(idx) def set_page_title(self, idx, title): """Set the tab title user data.""" - tabbar = self.tabBar() + tabbar = self._tab_bar() if config.cache['tabs.tooltips']: # always show only plain title in tooltips @@ -115,7 +128,7 @@ class TabWidget(QTabWidget): def page_title(self, idx): """Get the tab title user data.""" - return self.tabBar().page_title(idx) + return self._tab_bar().page_title(idx) def update_tab_title(self, idx, field=None): """Update the tab text for the given tab. @@ -126,7 +139,8 @@ class TabWidget(QTabWidget): is only set if the given field is in the template. """ assert idx != -1 - tab = self.widget(idx) + tab = self._tab_by_idx(idx) + assert tab is not None if tab.data.pinned: fmt = config.cache['tabs.title.format_pinned'] else: @@ -142,7 +156,7 @@ class TabWidget(QTabWidget): def left_align(num): return str(num).ljust(len(str(self.count()))) - bar = self.tabBar() + bar = self._tab_bar() cur_idx = bar.currentIndex() if idx == cur_idx: rel_idx = left_align(idx + 1) + " " @@ -164,14 +178,12 @@ class TabWidget(QTabWidget): def get_tab_fields(self, idx): """Get the tab field data.""" - tab = self.widget(idx) - if tab is None: - log.misc.debug( # type: ignore[unreachable] - "Got None-tab in get_tab_fields!") + tab = self._tab_by_idx(idx) + assert tab is not None page_title = self.page_title(idx) - fields = {} + fields: Dict[str, Any] = {} fields['id'] = tab.tab_id fields['current_title'] = page_title fields['title_sep'] = ' - ' if page_title else '' @@ -206,9 +218,7 @@ class TabWidget(QTabWidget): fields['protocol'] = url.scheme() y = tab.scroller.pos_perc()[1] - if y is None: - scroll_pos = '???' - elif y <= 0: + if y <= 0: scroll_pos = 'top' elif y >= 100: scroll_pos = 'bot' @@ -228,7 +238,7 @@ class TabWidget(QTabWidget): non-visible. To avoid flickering, disable repaint updates while we work. """ - bar = self.tabBar() + bar = self._tab_bar() toggle = (self.count() > 10 and not bar.drag_in_progress and bar.isVisible()) @@ -317,7 +327,7 @@ class TabWidget(QTabWidget): @pyqtSlot(int) def _on_current_changed(self, index): """Emit the tab_index_changed signal if the current tab changed.""" - self.tabBar().on_current_changed() + self._tab_bar().on_current_changed() self.update_tab_titles() self.tab_index_changed.emit(index, self.count()) @@ -332,16 +342,13 @@ class TabWidget(QTabWidget): Return: The tab URL as QUrl. """ - tab = self.widget(idx) - if tab is None: - url = QUrl() # type: ignore[unreachable] - else: - url = tab.url() + tab = self._tab_by_idx(idx) + url = QUrl() if tab is None else tab.url() # It's possible for url to be invalid, but the caller will handle that. qtutils.ensure_valid(url) return url - def update_tab_favicon(self, tab: QWidget) -> None: + def update_tab_favicon(self, tab: browsertab.AbstractTab) -> None: """Update favicon of the given tab.""" idx = self.indexOf(tab) @@ -353,11 +360,11 @@ class TabWidget(QTabWidget): def setTabIcon(self, idx: int, icon: QIcon) -> None: """Always show tab icons for pinned tabs in some circumstances.""" - tab = cast(Optional[browsertab.AbstractTab], self.widget(idx)) + tab = self._tab_by_idx(idx) if (icon.isNull() and config.cache['tabs.favicons.show'] != 'never' and config.cache['tabs.pinned.shrink'] and - not self.tabBar().vertical and + not self._tab_bar().vertical and tab is not None and tab.data.pinned): icon = self.style().standardIcon(QStyle.SP_FileIcon) super().setTabIcon(idx, icon) @@ -423,9 +430,15 @@ class TabBar(QTabBar): def __repr__(self): return utils.get_repr(self, count=self.count()) + def _tab_widget(self): + """Get the TabWidget we're in.""" + parent = self.parent() + assert isinstance(parent, TabWidget) + return parent + def _current_tab(self): """Get the current tab object.""" - return self.parent().currentWidget() + return self._tab_widget().currentWidget() @pyqtSlot(str) def _on_config_changed(self, option: str) -> None: @@ -627,7 +640,7 @@ class TabBar(QTabBar): raise IndexError("Tab index ({}) out of range ({})!".format( index, self.count())) - widget = self.parent().widget(index) + widget = self._tab_widget().widget(index) if widget is None: # This could happen when Qt calls tabSizeHint while initializing # tabs. |