summaryrefslogtreecommitdiff
path: root/qutebrowser/mainwindow
diff options
context:
space:
mode:
Diffstat (limited to 'qutebrowser/mainwindow')
-rw-r--r--qutebrowser/mainwindow/mainwindow.py10
-rw-r--r--qutebrowser/mainwindow/prompt.py4
-rw-r--r--qutebrowser/mainwindow/statusbar/bar.py5
-rw-r--r--qutebrowser/mainwindow/statusbar/command.py3
-rw-r--r--qutebrowser/mainwindow/statusbar/url.py3
-rw-r--r--qutebrowser/mainwindow/tabbedbrowser.py79
-rw-r--r--qutebrowser/mainwindow/tabwidget.py73
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.