From 21bef1058ddd6b8f4d7f9f281ade69243e7b027c Mon Sep 17 00:00:00 2001 From: Lee Miller Date: Tue, 14 May 2024 17:38:43 +0300 Subject: [PATCH 1/7] Improve the base class for bitmessageqt test cases --- src/bitmessageqt/tests/__init__.py | 8 ++++---- src/bitmessageqt/tests/main.py | 23 +++++++++++++++++------ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/bitmessageqt/tests/__init__.py b/src/bitmessageqt/tests/__init__.py index a542abdc..a81ddb04 100644 --- a/src/bitmessageqt/tests/__init__.py +++ b/src/bitmessageqt/tests/__init__.py @@ -1,9 +1,9 @@ """bitmessageqt tests""" -from addressbook import TestAddressbook -from main import TestMain, TestUISignaler -from settings import TestSettings -from support import TestSupport +from .addressbook import TestAddressbook +from .main import TestMain, TestUISignaler +from .settings import TestSettings +from .support import TestSupport __all__ = [ "TestAddressbook", "TestMain", "TestSettings", "TestSupport", diff --git a/src/bitmessageqt/tests/main.py b/src/bitmessageqt/tests/main.py index b3aa67fa..d3fda8aa 100644 --- a/src/bitmessageqt/tests/main.py +++ b/src/bitmessageqt/tests/main.py @@ -1,19 +1,23 @@ """Common definitions for bitmessageqt tests""" -import Queue import sys import unittest from PyQt4 import QtCore, QtGui +from six.moves import queue import bitmessageqt -import queues -from tr import _translate +from bitmessageqt import _translate, config, queues class TestBase(unittest.TestCase): """Base class for bitmessageqt test case""" + @classmethod + def setUpClass(cls): + """Provide the UI test cases with common settings""" + cls.config = config + def setUp(self): self.app = ( QtGui.QApplication.instance() @@ -24,14 +28,21 @@ class TestBase(unittest.TestCase): self.window.appIndicatorInit(self.app) def tearDown(self): + """Search for exceptions in closures called by timer and fail if any""" # self.app.deleteLater() + concerning = [] while True: try: thread, exc = queues.excQueue.get(block=False) - except Queue.Empty: - return + except queue.Empty: + break if thread == 'tests': - self.fail('Exception in the main thread: %s' % exc) + concerning.append(exc) + if concerning: + self.fail( + 'Exceptions found in the main thread:\n%s' % '\n'.join(( + str(e) for e in concerning + ))) class TestMain(unittest.TestCase): -- 2.45.1 From ec1b05ee90860885e585bbb9c317f5e5306d6490 Mon Sep 17 00:00:00 2001 From: Lee Miller Date: Thu, 25 Apr 2024 22:14:50 +0300 Subject: [PATCH 2/7] Allow user to set a base Qt window style and the font (family and size only) --- src/bitmessageqt/__init__.py | 9 +++++++++ src/bitmessageqt/settings.py | 39 ++++++++++++++++++++++++++++++++++++ src/bitmessageqt/settings.ui | 32 +++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 40113b5a..7f767b03 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -4241,6 +4241,15 @@ class BitmessageQtApplication(QtGui.QApplication): QtCore.QCoreApplication.setOrganizationDomain("bitmessage.org") QtCore.QCoreApplication.setApplicationName("pybitmessageqt") + self.setStyle( + config.safeGet('bitmessagesettings', 'windowstyle', 'GTK+')) + + font = config.safeGet('bitmessagesettings', 'font') + if font: + # family, size, weight = font.split(',') + family, size = font.split(',') + self.setFont(QtGui.QFont(family, int(size))) + self.server = None self.is_running = False diff --git a/src/bitmessageqt/settings.py b/src/bitmessageqt/settings.py index 3d05db25..44cad4c9 100644 --- a/src/bitmessageqt/settings.py +++ b/src/bitmessageqt/settings.py @@ -49,6 +49,7 @@ class SettingsDialog(QtGui.QDialog): self.firstrun = firstrun self.config = config_obj self.net_restart_needed = False + self.font_setting = None self.timer = QtCore.QTimer() if self.config.safeGetBoolean('bitmessagesettings', 'dontconnect'): @@ -85,6 +86,16 @@ class SettingsDialog(QtGui.QDialog): def adjust_from_config(self, config): """Adjust all widgets state according to config settings""" # pylint: disable=too-many-branches,too-many-statements + + current_style = config.safeGet( + 'bitmessagesettings', 'windowstyle', 'GTK+') + for i, sk in enumerate(QtGui.QStyleFactory.keys()): + self.comboBoxStyle.addItem(sk) + if sk == current_style: + self.comboBoxStyle.setCurrentIndex(i) + + self.save_font_setting(QtGui.QApplication.instance().font()) + if not self.parent.tray.isSystemTrayAvailable(): self.groupBoxTray.setEnabled(False) self.groupBoxTray.setTitle(_translate( @@ -322,6 +333,18 @@ class SettingsDialog(QtGui.QDialog): if status == 'success': self.parent.namecoin = nc + def save_font_setting(self, font): + """Save user font setting and set the buttonFont text""" + font_setting = (font.family(), font.pointSize()) + self.buttonFont.setText('{} {}'.format(*font_setting)) + self.font_setting = '{},{}'.format(*font_setting) + + def choose_font(self): + """Show the font selection dialog""" + font, valid = QtGui.QFontDialog.getFont() + if valid: + self.save_font_setting(font) + def accept(self): """A callback for accepted event of buttonBox (OK button pressed)""" # pylint: disable=too-many-branches,too-many-statements @@ -348,6 +371,22 @@ class SettingsDialog(QtGui.QDialog): self.config.set('bitmessagesettings', 'replybelow', str( self.checkBoxReplyBelow.isChecked())) + window_style = str(self.comboBoxStyle.currentText()) + if self.config.safeGet( + 'bitmessagesettings', 'windowstyle', 'GTK+' + ) != window_style or self.config.safeGet( + 'bitmessagesettings', 'font' + ) != self.font_setting: + self.config.set('bitmessagesettings', 'windowstyle', window_style) + self.config.set('bitmessagesettings', 'font', self.font_setting) + queues.UISignalQueue.put(( + 'updateStatusBar', ( + _translate( + "MainWindow", + "You need to restart the application to apply" + " the window style or default font."), 1) + )) + lang = str(self.languageComboBox.itemData( self.languageComboBox.currentIndex()).toString()) self.config.set('bitmessagesettings', 'userlocale', lang) diff --git a/src/bitmessageqt/settings.ui b/src/bitmessageqt/settings.ui index 1e9a6f09..e7ce1d71 100644 --- a/src/bitmessageqt/settings.ui +++ b/src/bitmessageqt/settings.ui @@ -147,6 +147,32 @@ + + + + Custom Style + + + + + + + 100 + 0 + + + + + + + + Font + + + + + + @@ -1202,5 +1228,11 @@ + + buttonFont + clicked() + settingsDialog + choose_font + -- 2.45.1 From 0ccbf6832fcff8ef0dba00ab6a57290c6bbc5939 Mon Sep 17 00:00:00 2001 From: Lee Miller Date: Thu, 2 May 2024 18:36:15 +0300 Subject: [PATCH 3/7] Adjust the tabWidget font size relative to the base app font --- src/bitmessageqt/bitmessageui.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index 961fc093..bee8fd57 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -61,7 +61,8 @@ class Ui_MainWindow(object): self.tabWidget.setMinimumSize(QtCore.QSize(0, 0)) self.tabWidget.setBaseSize(QtCore.QSize(0, 0)) font = QtGui.QFont() - font.setPointSize(9) + base_size = QtGui.QApplication.instance().font().pointSize() + font.setPointSize(int(base_size * 0.75)) self.tabWidget.setFont(font) self.tabWidget.setTabPosition(QtGui.QTabWidget.North) self.tabWidget.setTabShape(QtGui.QTabWidget.Rounded) -- 2.45.1 From d46af0835a0a015042e017680c6f361a049f3aaa Mon Sep 17 00:00:00 2001 From: Lee Miller Date: Sat, 4 May 2024 00:07:29 +0300 Subject: [PATCH 4/7] A rather rudimentary test with basic checks for the style setting --- src/bitmessageqt/tests/settings.py | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/tests/settings.py b/src/bitmessageqt/tests/settings.py index 0dcf8cf3..3c14183f 100644 --- a/src/bitmessageqt/tests/settings.py +++ b/src/bitmessageqt/tests/settings.py @@ -1,3 +1,4 @@ +"""Tests for PyBitmessage settings""" import threading import time @@ -14,8 +15,7 @@ class TestSettings(TestBase): def test_udp(self): """Test the effect of checkBoxUDP""" - udp_setting = config.safeGetBoolean( - 'bitmessagesettings', 'udp') + udp_setting = config.safeGetBoolean('bitmessagesettings', 'udp') self.assertEqual(udp_setting, self.dialog.checkBoxUDP.isChecked()) self.dialog.checkBoxUDP.setChecked(not udp_setting) self.dialog.accept() @@ -32,3 +32,22 @@ class TestSettings(TestBase): else: if not udp_setting: self.fail('No Announcer thread found while udp set to True') + + def test_styling(self): + """Test custom windows style and font""" + style_setting = config.safeGet('bitmessagesettings', 'windowstyle') + font_setting = config.safeGet('bitmessagesettings', 'font') + self.assertIs(style_setting, None) + self.assertIs(font_setting, None) + style_control = self.dialog.comboBoxStyle + self.assertEqual(style_control.currentText(), 'GTK+') + style_count = style_control.count() + self.assertGreater(style_count, 1) + for i in range(style_count): + if i != style_control.currentIndex(): + style_control.setCurrentIndex(i) + break + self.dialog.accept() + self.assertEqual( + config.safeGet('bitmessagesettings', 'windowstyle'), + style_control.currentText()) -- 2.45.1 From c3c41902cf0f05d570d34ea12b1b97c58f5af482 Mon Sep 17 00:00:00 2001 From: Lee Miller Date: Wed, 8 May 2024 01:01:39 +0300 Subject: [PATCH 5/7] Use QtTest and QTimer.singleShot() to check the font dialog --- src/bitmessageqt/tests/settings.py | 34 +++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/src/bitmessageqt/tests/settings.py b/src/bitmessageqt/tests/settings.py index 3c14183f..170f8f40 100644 --- a/src/bitmessageqt/tests/settings.py +++ b/src/bitmessageqt/tests/settings.py @@ -2,10 +2,13 @@ import threading import time -from main import TestBase +from PyQt4 import QtCore, QtGui, QtTest + from bmconfigparser import config from bitmessageqt import settings +from .main import TestBase + class TestSettings(TestBase): """A test case for the "Settings" dialog""" @@ -41,13 +44,34 @@ class TestSettings(TestBase): self.assertIs(font_setting, None) style_control = self.dialog.comboBoxStyle self.assertEqual(style_control.currentText(), 'GTK+') + + def call_font_dialog(): + """A function to get the open font dialog and accept it""" + font_dialog = QtGui.QApplication.activeModalWidget() + self.assertTrue(isinstance(font_dialog, QtGui.QFontDialog)) + selected_font = font_dialog.currentFont() + self.assertEqual( + config.safeGet('bitmessagesettings', 'font'), '{},{}'.format( + selected_font.family(), selected_font.pointSize())) + + font_dialog.accept() + self.dialog.accept() + self.assertEqual( + config.safeGet('bitmessagesettings', 'windowstyle'), + style_control.currentText()) + + def click_font_button(): + """Use QtTest to click the button""" + QtTest.QTest.mouseClick( + self.dialog.buttonFont, QtCore.Qt.LeftButton) + style_count = style_control.count() self.assertGreater(style_count, 1) for i in range(style_count): if i != style_control.currentIndex(): style_control.setCurrentIndex(i) break - self.dialog.accept() - self.assertEqual( - config.safeGet('bitmessagesettings', 'windowstyle'), - style_control.currentText()) + + QtCore.QTimer.singleShot(30, click_font_button) + QtCore.QTimer.singleShot(60, call_font_dialog) + time.sleep(2) -- 2.45.1 From de11bc484cd31e340d70e3690d584d189bf99cc5 Mon Sep 17 00:00:00 2001 From: Lee Miller Date: Sun, 9 Jun 2024 22:17:14 +0300 Subject: [PATCH 6/7] Make Windows the default window style on windows, not GTK+ --- src/bitmessageqt/__init__.py | 18 ++++++++++++++---- src/bitmessageqt/settings.py | 12 +++++------- src/bitmessageqt/tests/settings.py | 3 ++- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 7f767b03..1b1a7885 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -62,6 +62,9 @@ except ImportError: get_plugins = False +is_windows = sys.platform.startswith('win') + + # TODO: rewrite def powQueueSize(): """Returns the size of queues.workerQueue including current unfinished work""" @@ -80,7 +83,7 @@ def openKeysFile(): keysfile = os.path.join(state.appdata, 'keys.dat') if 'linux' in sys.platform: subprocess.call(["xdg-open", keysfile]) - elif sys.platform.startswith('win'): + elif is_windows: os.startfile(keysfile) # pylint: disable=no-member @@ -868,7 +871,7 @@ class MyForm(settingsmixin.SMainWindow): """ startonlogon = config.safeGetBoolean( 'bitmessagesettings', 'startonlogon') - if sys.platform.startswith('win'): # Auto-startup for Windows + if is_windows: # Auto-startup for Windows RUN_PATH = "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run" settings = QtCore.QSettings( RUN_PATH, QtCore.QSettings.NativeFormat) @@ -4233,6 +4236,14 @@ class BitmessageQtApplication(QtGui.QApplication): # Unique identifier for this application uuid = '6ec0149b-96e1-4be1-93ab-1465fb3ebf7c' + @staticmethod + def get_windowstyle(): + """Get window style set in config or default""" + return config.safeGet( + 'bitmessagesettings', 'windowstyle', + 'Windows' if is_windows else 'GTK+' + ) + def __init__(self, *argv): super(BitmessageQtApplication, self).__init__(*argv) id = BitmessageQtApplication.uuid @@ -4241,8 +4252,7 @@ class BitmessageQtApplication(QtGui.QApplication): QtCore.QCoreApplication.setOrganizationDomain("bitmessage.org") QtCore.QCoreApplication.setApplicationName("pybitmessageqt") - self.setStyle( - config.safeGet('bitmessagesettings', 'windowstyle', 'GTK+')) + self.setStyle(self.get_windowstyle()) font = config.safeGet('bitmessagesettings', 'font') if font: diff --git a/src/bitmessageqt/settings.py b/src/bitmessageqt/settings.py index 44cad4c9..eec3d69f 100644 --- a/src/bitmessageqt/settings.py +++ b/src/bitmessageqt/settings.py @@ -45,6 +45,7 @@ class SettingsDialog(QtGui.QDialog): super(SettingsDialog, self).__init__(parent) widgets.load('settings.ui', self) + self.app = QtGui.QApplication.instance() self.parent = parent self.firstrun = firstrun self.config = config_obj @@ -87,14 +88,13 @@ class SettingsDialog(QtGui.QDialog): """Adjust all widgets state according to config settings""" # pylint: disable=too-many-branches,too-many-statements - current_style = config.safeGet( - 'bitmessagesettings', 'windowstyle', 'GTK+') + current_style = self.app.get_windowstyle() for i, sk in enumerate(QtGui.QStyleFactory.keys()): self.comboBoxStyle.addItem(sk) if sk == current_style: self.comboBoxStyle.setCurrentIndex(i) - self.save_font_setting(QtGui.QApplication.instance().font()) + self.save_font_setting(self.app.font()) if not self.parent.tray.isSystemTrayAvailable(): self.groupBoxTray.setEnabled(False) @@ -148,7 +148,7 @@ class SettingsDialog(QtGui.QDialog): "MainWindow", "Tray notifications not yet supported on your OS.")) - if 'win' not in sys.platform and not self.parent.desktop: + if not sys.platform.startswith('win') and not self.parent.desktop: self.checkBoxStartOnLogon.setDisabled(True) self.checkBoxStartOnLogon.setText(_translate( "MainWindow", "Start-on-login not yet supported on your OS.")) @@ -372,9 +372,7 @@ class SettingsDialog(QtGui.QDialog): self.checkBoxReplyBelow.isChecked())) window_style = str(self.comboBoxStyle.currentText()) - if self.config.safeGet( - 'bitmessagesettings', 'windowstyle', 'GTK+' - ) != window_style or self.config.safeGet( + if self.app.get_windowstyle() != window_style or self.config.safeGet( 'bitmessagesettings', 'font' ) != self.font_setting: self.config.set('bitmessagesettings', 'windowstyle', window_style) diff --git a/src/bitmessageqt/tests/settings.py b/src/bitmessageqt/tests/settings.py index 170f8f40..bad28ed7 100644 --- a/src/bitmessageqt/tests/settings.py +++ b/src/bitmessageqt/tests/settings.py @@ -43,7 +43,8 @@ class TestSettings(TestBase): self.assertIs(style_setting, None) self.assertIs(font_setting, None) style_control = self.dialog.comboBoxStyle - self.assertEqual(style_control.currentText(), 'GTK+') + self.assertEqual( + style_control.currentText(), self.app.get_windowstyle()) def call_font_dialog(): """A function to get the open font dialog and accept it""" -- 2.45.1 From de445d6bd9d18894f20dbc8ed19c509d0ac7c71d Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 16 Jun 2024 11:44:18 +0800 Subject: [PATCH 7/7] Suppress pylint complaint --- src/bitmessageqt/settings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bitmessageqt/settings.py b/src/bitmessageqt/settings.py index eec3d69f..eeb507c7 100644 --- a/src/bitmessageqt/settings.py +++ b/src/bitmessageqt/settings.py @@ -41,6 +41,7 @@ def getSOCKSProxyType(config): class SettingsDialog(QtGui.QDialog): """The "Settings" dialog""" + # pylint: disable=too-many-instance-attributes def __init__(self, parent=None, firstrun=False): super(SettingsDialog, self).__init__(parent) widgets.load('settings.ui', self) -- 2.45.1