From 8d88dd9d75138b68cc28e831ad28071c79fdcf9c Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 22 Oct 2015 21:33:50 +0200 Subject: [PATCH 1/7] Fix crash with small icons Fixes #1015 --- qutebrowser/mainwindow/tabwidget.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qutebrowser/mainwindow/tabwidget.py b/qutebrowser/mainwindow/tabwidget.py index 46a8e48d6..42f393471 100644 --- a/qutebrowser/mainwindow/tabwidget.py +++ b/qutebrowser/mainwindow/tabwidget.py @@ -629,7 +629,7 @@ class TabBarStyle(QCommonStyle): # any sophisticated drawing. super().drawControl(QStyle.CE_TabBarTabShape, opt, p, widget) elif element == QStyle.CE_TabBarTabLabel: - if not opt.icon.isNull(): + if not opt.icon.isNull() and layouts.icon.isValid(): self._draw_icon(layouts, opt, p) alignment = Qt.AlignLeft | Qt.AlignVCenter | Qt.TextHideMnemonic self._style.drawItemText(p, layouts.text, alignment, opt.palette, @@ -721,7 +721,8 @@ class TabBarStyle(QCommonStyle): else: icon_padding = self.pixelMetric(PixelMetrics.icon_padding, opt) icon_rect = self._get_icon_rect(opt, text_rect) - text_rect.adjust(icon_rect.width() + icon_padding, 0, 0, 0) + if icon_rect.isValid(): + text_rect.adjust(icon_rect.width() + icon_padding, 0, 0, 0) text_rect = self._style.visualRect(opt.direction, opt.rect, text_rect) return Layouts(text=text_rect, icon=icon_rect, @@ -751,5 +752,4 @@ class TabBarStyle(QCommonStyle): icon_rect = QRect(text_rect.left(), text_rect.top() + 1, tab_icon_size.width(), tab_icon_size.height()) icon_rect = self._style.visualRect(opt.direction, opt.rect, icon_rect) - qtutils.ensure_valid(icon_rect) return icon_rect From 7a413ad6d5d0c067f4cca3d8d4935cdeb5d83e10 Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 22 Oct 2015 23:03:28 +0200 Subject: [PATCH 2/7] Remove unneeded functions from TabBar. addTab() and insertTab() are not called and if they were called would raise an exception (self.set_page_title not defined). --- qutebrowser/mainwindow/tabwidget.py | 53 ----------------------------- 1 file changed, 53 deletions(-) diff --git a/qutebrowser/mainwindow/tabwidget.py b/qutebrowser/mainwindow/tabwidget.py index 42f393471..9a29b6838 100644 --- a/qutebrowser/mainwindow/tabwidget.py +++ b/qutebrowser/mainwindow/tabwidget.py @@ -465,59 +465,6 @@ class TabBar(QTabBar): super().tabRemoved(idx) self._tabhide() - def addTab(self, icon_or_text, text_or_empty=None): - """Override addTab to use our own text setting logic. - - Unfortunately QTabBar::addTab has these two overloads: - - const QIcon & icon, const QString & label - - const QString & label - - This means we'll get different arguments based on the chosen overload. - - Args: - icon_or_text: Either the QIcon to add or the label. - text_or_empty: Either the label or None. - - Return: - The index of the newly added tab. - """ - if text_or_empty is None: - icon = None - text = icon_or_text - new_idx = super().addTab('') - else: - icon = icon_or_text - text = text_or_empty - new_idx = super().addTab(icon, '') - self.set_page_title(new_idx, text) - - def insertTab(self, idx, icon_or_text, text_or_empty=None): - """Override insertTab to use our own text setting logic. - - Unfortunately QTabBar::insertTab has these two overloads: - - int index, const QIcon & icon, const QString & label - - int index, const QString & label - - This means we'll get different arguments based on the chosen overload. - - Args: - idx: Where to insert the widget. - icon_or_text: Either the QIcon to add or the label. - text_or_empty: Either the label or None. - - Return: - The index of the newly added tab. - """ - if text_or_empty is None: - icon = None - text = icon_or_text - new_idx = super().InsertTab(idx, '') - else: - icon = icon_or_text - text = text_or_empty - new_idx = super().insertTab(idx, icon, '') - self.set_page_title(new_idx, text) - def wheelEvent(self, e): """Override wheelEvent to make the action configurable. From 0851999b8985998309f6129416d9648d31daa927 Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 23 Oct 2015 14:01:22 +0200 Subject: [PATCH 3/7] Add unit/regression test --- tests/helpers/stubs.py | 15 +++++++- tests/unit/mainwindow/test_tabwidget.py | 50 +++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 tests/unit/mainwindow/test_tabwidget.py diff --git a/tests/helpers/stubs.py b/tests/helpers/stubs.py index 58e88a81e..844de59a2 100644 --- a/tests/helpers/stubs.py +++ b/tests/helpers/stubs.py @@ -26,8 +26,9 @@ from unittest import mock from PyQt5.QtCore import pyqtSignal, QPoint, QProcess, QObject from PyQt5.QtNetwork import (QNetworkRequest, QAbstractNetworkCache, QNetworkCacheMetaData) -from PyQt5.QtWidgets import QCommonStyle +from PyQt5.QtWidgets import QCommonStyle, QWidget +from qutebrowser.browser import webview from qutebrowser.config import configexc @@ -204,6 +205,18 @@ def fake_qprocess(): return m +class FakeWebView(QWidget): + + """Fake WebView which can be added to a tab.""" + + def __init__(self): + super().__init__() + self.progress = 0 + self.scroll_pos = (-1, -1) + self.load_status = webview.LoadStatus.none + self.tab_id = 0 + + class FakeSignal: """Fake pyqtSignal stub which does nothing. diff --git a/tests/unit/mainwindow/test_tabwidget.py b/tests/unit/mainwindow/test_tabwidget.py new file mode 100644 index 000000000..4cf817123 --- /dev/null +++ b/tests/unit/mainwindow/test_tabwidget.py @@ -0,0 +1,50 @@ +# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et: + +# Copyright 2015 Daniel Schadt +# +# This file is part of qutebrowser. +# +# qutebrowser is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# qutebrowser is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with qutebrowser. If not, see . + +"""Tests for the custom TabWidget/TabBar.""" + +import pytest +import functools + +from qutebrowser.mainwindow import tabwidget +from PyQt5.QtGui import QIcon, QPixmap + + +class TestTabWidget: + + """Tests for TabBar.""" + + @pytest.fixture + def widget(self, qtbot, default_config): + w = tabwidget.TabWidget(0) + qtbot.addWidget(w) + return w + + def test_small_icon_doesnt_crash(self, widget, qtbot, stubs): + """Test that setting a small icon doesn't produce a crash. + + Regression test for #1015. + """ + # Size taken from issue report + pixmap = QPixmap(72, 1) + icon = QIcon(pixmap) + page = stubs.FakeWebView() + widget.addTab(page, icon, 'foobar') + widget.show() + qtbot.waitForWindowShown(widget) From 279d0926ee6d3df086f22cf2f1dddbd013593ed3 Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 23 Oct 2015 19:36:21 +0200 Subject: [PATCH 4/7] Remove unused import, make pylint happy --- tests/unit/mainwindow/test_tabwidget.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/unit/mainwindow/test_tabwidget.py b/tests/unit/mainwindow/test_tabwidget.py index 4cf817123..c8baf2692 100644 --- a/tests/unit/mainwindow/test_tabwidget.py +++ b/tests/unit/mainwindow/test_tabwidget.py @@ -20,7 +20,6 @@ """Tests for the custom TabWidget/TabBar.""" import pytest -import functools from qutebrowser.mainwindow import tabwidget from PyQt5.QtGui import QIcon, QPixmap From 9722d4ba0312da75c291542b7c0bcd62349c6f5a Mon Sep 17 00:00:00 2001 From: Daniel Date: Sat, 24 Oct 2015 01:32:01 +0200 Subject: [PATCH 5/7] test_tabwidget: Make config_stub explicit ... also call TabWidget.close() at the end of the test. --- tests/unit/mainwindow/test_tabwidget.py | 31 ++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/tests/unit/mainwindow/test_tabwidget.py b/tests/unit/mainwindow/test_tabwidget.py index c8baf2692..bf7ffb383 100644 --- a/tests/unit/mainwindow/test_tabwidget.py +++ b/tests/unit/mainwindow/test_tabwidget.py @@ -22,15 +22,39 @@ import pytest from qutebrowser.mainwindow import tabwidget -from PyQt5.QtGui import QIcon, QPixmap +from qutebrowser.config import configtypes +from PyQt5.QtGui import QIcon, QPixmap, QFont, QColor class TestTabWidget: - """Tests for TabBar.""" + """Tests for TabWidget.""" + + CONFIG = { + 'fonts': { + 'tabbar': QFont(), + }, + 'tabs': { + 'show-switching-delay': 800, + 'movable': True, + 'position': 0, + 'select-on-remove': 1, + 'show': 'always', + 'padding': configtypes.PaddingValues(0, 0, 5, 5), + 'indicator-width': 3, + 'indicator-padding': configtypes.PaddingValues(2, 2, 0, 4), + 'title-format': '{index}: {title}', + }, + 'colors': { + 'tabs.bg.bar': QColor(), + 'tabs.bg.selected.even': QColor(), + 'tabs.fg.selected.even': QColor(), + } + } @pytest.fixture - def widget(self, qtbot, default_config): + def widget(self, qtbot, config_stub): + config_stub.data = self.CONFIG w = tabwidget.TabWidget(0) qtbot.addWidget(w) return w @@ -47,3 +71,4 @@ class TestTabWidget: widget.addTab(page, icon, 'foobar') widget.show() qtbot.waitForWindowShown(widget) + widget.close() From cdb9c0998fd4d0e6e20a4137e518bbc441109f85 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sat, 24 Oct 2015 08:07:43 +0200 Subject: [PATCH 6/7] Add a comment for close() call. --- tests/unit/mainwindow/test_tabwidget.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/unit/mainwindow/test_tabwidget.py b/tests/unit/mainwindow/test_tabwidget.py index bf7ffb383..6d5dd9cb5 100644 --- a/tests/unit/mainwindow/test_tabwidget.py +++ b/tests/unit/mainwindow/test_tabwidget.py @@ -71,4 +71,8 @@ class TestTabWidget: widget.addTab(page, icon, 'foobar') widget.show() qtbot.waitForWindowShown(widget) + # We need to call close() here because closing needs the stubbed config + # on OS X, but when qtbot closes it, the config stub is already gone. + # WORKAROUND for https://github.com/pytest-dev/pytest-qt/issues/106 + # https://github.com/The-Compiler/qutebrowser/pull/1048#issuecomment-150660769 widget.close() From 343e0b89c01dc0d08d00bbef97139e70b3227c37 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sat, 24 Oct 2015 08:07:52 +0200 Subject: [PATCH 7/7] Regenerate authors. --- README.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.asciidoc b/README.asciidoc index 7f1941703..1b0a186df 100644 --- a/README.asciidoc +++ b/README.asciidoc @@ -141,9 +141,9 @@ Contributors, sorted by the number of commits in descending order: * Martin Tournoij * Raphael Pierzina * Joel Torstensson +* Daniel * Claude * Lamar Pavel -* Daniel * Nathan Isom * Austin Anderson * Artur Shaik