diff options
Diffstat (limited to 'silx/gui/utils')
-rwxr-xr-x[-rw-r--r--] | silx/gui/utils/__init__.py | 32 | ||||
-rwxr-xr-x | silx/gui/utils/qtutils.py | 170 | ||||
-rwxr-xr-x[-rw-r--r--] | silx/gui/utils/test/__init__.py | 12 | ||||
-rw-r--r-- | silx/gui/utils/test/test.py | 76 | ||||
-rwxr-xr-x | silx/gui/utils/test/test_qtutils.py | 75 | ||||
-rw-r--r-- | silx/gui/utils/test/test_testutils.py | 55 | ||||
-rw-r--r-- | silx/gui/utils/testutils.py | 3 |
7 files changed, 418 insertions, 5 deletions
diff --git a/silx/gui/utils/__init__.py b/silx/gui/utils/__init__.py index 51c4fac..a4e442f 100644..100755 --- a/silx/gui/utils/__init__.py +++ b/silx/gui/utils/__init__.py @@ -1,7 +1,7 @@ # coding: utf-8 # /*########################################################################## # -# Copyright (c) 2018 European Synchrotron Radiation Facility +# Copyright (c) 2018-2019 European Synchrotron Radiation Facility # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -27,3 +27,33 @@ __authors__ = ["T. Vincent"] __license__ = "MIT" __date__ = "09/03/2018" + + +import contextlib as _contextlib + + +@_contextlib.contextmanager +def blockSignals(*objs): + """Context manager blocking signals of QObjects. + + It restores previous state when leaving. + + :param qt.QObject objs: QObjects for which to block signals + """ + blocked = [(obj, obj.blockSignals(True)) for obj in objs] + try: + yield + finally: + for obj, previous in blocked: + obj.blockSignals(previous) + + +def getQEventName(eventType): + """ + Returns the name of a QEvent. + + :param Union[int,qt.QEvent] eventType: A QEvent or a QEvent type. + :returns: str + """ + from . import qtutils + return qtutils.getQEventName(eventType) diff --git a/silx/gui/utils/qtutils.py b/silx/gui/utils/qtutils.py new file mode 100755 index 0000000..eb823a8 --- /dev/null +++ b/silx/gui/utils/qtutils.py @@ -0,0 +1,170 @@ +from silx.gui import qt
+
+
+QT_EVENT_NAMES = {
+ 0: "None",
+ 114: "ActionAdded",
+ 113: "ActionChanged",
+ 115: "ActionRemoved",
+ 99: "ActivationChange",
+ 121: "ApplicationActivate",
+ # ApplicationActivate: "ApplicationActivated",
+ 122: "ApplicationDeactivate",
+ 36: "ApplicationFontChange",
+ 37: "ApplicationLayoutDirectionChange",
+ 38: "ApplicationPaletteChange",
+ 214: "ApplicationStateChange",
+ 35: "ApplicationWindowIconChange",
+ 68: "ChildAdded",
+ 69: "ChildPolished",
+ 71: "ChildRemoved",
+ 40: "Clipboard",
+ 19: "Close",
+ 200: "CloseSoftwareInputPanel",
+ 178: "ContentsRectChange",
+ 82: "ContextMenu",
+ 183: "CursorChange",
+ 52: "DeferredDelete",
+ 60: "DragEnter",
+ 62: "DragLeave",
+ 61: "DragMove",
+ 63: "Drop",
+ 170: "DynamicPropertyChange",
+ 98: "EnabledChange",
+ 10: "Enter",
+ 150: "EnterEditFocus",
+ 124: "EnterWhatsThisMode",
+ 206: "Expose",
+ 116: "FileOpen",
+ 8: "FocusIn",
+ 9: "FocusOut",
+ 23: "FocusAboutToChange",
+ 97: "FontChange",
+ 198: "Gesture",
+ 202: "GestureOverride",
+ 188: "GrabKeyboard",
+ 186: "GrabMouse",
+ 159: "GraphicsSceneContextMenu",
+ 164: "GraphicsSceneDragEnter",
+ 166: "GraphicsSceneDragLeave",
+ 165: "GraphicsSceneDragMove",
+ 167: "GraphicsSceneDrop",
+ 163: "GraphicsSceneHelp",
+ 160: "GraphicsSceneHoverEnter",
+ 162: "GraphicsSceneHoverLeave",
+ 161: "GraphicsSceneHoverMove",
+ 158: "GraphicsSceneMouseDoubleClick",
+ 155: "GraphicsSceneMouseMove",
+ 156: "GraphicsSceneMousePress",
+ 157: "GraphicsSceneMouseRelease",
+ 182: "GraphicsSceneMove",
+ 181: "GraphicsSceneResize",
+ 168: "GraphicsSceneWheel",
+ 18: "Hide",
+ 27: "HideToParent",
+ 127: "HoverEnter",
+ 128: "HoverLeave",
+ 129: "HoverMove",
+ 96: "IconDrag",
+ 101: "IconTextChange",
+ 83: "InputMethod",
+ 207: "InputMethodQuery",
+ 169: "KeyboardLayoutChange",
+ 6: "KeyPress",
+ 7: "KeyRelease",
+ 89: "LanguageChange",
+ 90: "LayoutDirectionChange",
+ 76: "LayoutRequest",
+ 11: "Leave",
+ 151: "LeaveEditFocus",
+ 125: "LeaveWhatsThisMode",
+ 88: "LocaleChange",
+ 176: "NonClientAreaMouseButtonDblClick",
+ 174: "NonClientAreaMouseButtonPress",
+ 175: "NonClientAreaMouseButtonRelease",
+ 173: "NonClientAreaMouseMove",
+ 177: "MacSizeChange",
+ 43: "MetaCall",
+ 102: "ModifiedChange",
+ 4: "MouseButtonDblClick",
+ 2: "MouseButtonPress",
+ 3: "MouseButtonRelease",
+ 5: "MouseMove",
+ 109: "MouseTrackingChange",
+ 13: "Move",
+ 197: "NativeGesture",
+ 208: "OrientationChange",
+ 12: "Paint",
+ 39: "PaletteChange",
+ 131: "ParentAboutToChange",
+ 21: "ParentChange",
+ 212: "PlatformPanel",
+ 217: "PlatformSurface",
+ 75: "Polish",
+ 74: "PolishRequest",
+ 123: "QueryWhatsThis",
+ 106: "ReadOnlyChange",
+ 199: "RequestSoftwareInputPanel",
+ 14: "Resize",
+ 204: "ScrollPrepare",
+ 205: "Scroll",
+ 117: "Shortcut",
+ 51: "ShortcutOverride",
+ 17: "Show",
+ 26: "ShowToParent",
+ 50: "SockAct",
+ 192: "StateMachineSignal",
+ 193: "StateMachineWrapped",
+ 112: "StatusTip",
+ 100: "StyleChange",
+ 87: "TabletMove",
+ 92: "TabletPress",
+ 93: "TabletRelease",
+ 171: "TabletEnterProximity",
+ 172: "TabletLeaveProximity",
+ 219: "TabletTrackingChange",
+ 22: "ThreadChange",
+ 1: "Timer",
+ 120: "ToolBarChange",
+ 110: "ToolTip",
+ 184: "ToolTipChange",
+ 194: "TouchBegin",
+ 209: "TouchCancel",
+ 196: "TouchEnd",
+ 195: "TouchUpdate",
+ 189: "UngrabKeyboard",
+ 187: "UngrabMouse",
+ 78: "UpdateLater",
+ 77: "UpdateRequest",
+ 111: "WhatsThis",
+ 118: "WhatsThisClicked",
+ 31: "Wheel",
+ 132: "WinEventAct",
+ 24: "WindowActivate",
+ 103: "WindowBlocked",
+ 25: "WindowDeactivate",
+ 34: "WindowIconChange",
+ 105: "WindowStateChange",
+ 33: "WindowTitleChange",
+ 104: "WindowUnblocked",
+ 203: "WinIdChange",
+ 126: "ZOrderChange",
+ 65535: "MaxUser",
+}
+
+
+def getQEventName(eventType):
+ """
+ Returns the name of a QEvent.
+
+ :param Union[int,qt.QEvent] eventType: A QEvent or a QEvent type.
+ :returns: str
+ """
+ if isinstance(eventType, qt.QEvent):
+ eventType = eventType.type()
+ if 1000 <= eventType <= 65535:
+ return "User_%d" % eventType
+ name = QT_EVENT_NAMES.get(eventType, None)
+ if name is not None:
+ return name
+ return "Unknown_%d" % eventType
diff --git a/silx/gui/utils/test/__init__.py b/silx/gui/utils/test/__init__.py index 9e50170..d500c05 100644..100755 --- a/silx/gui/utils/test/__init__.py +++ b/silx/gui/utils/test/__init__.py @@ -1,7 +1,7 @@ # coding: utf-8 # /*########################################################################## # -# Copyright (c) 2018 European Synchrotron Radiation Facility +# Copyright (c) 2018-2019 European Synchrotron Radiation Facility # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -34,15 +34,21 @@ import unittest from . import test_async from . import test_image +from . import test_qtutils +from . import test_testutils +from . import test def suite(): """Test suite for module silx.image.test""" test_suite = unittest.TestSuite() + test_suite.addTest(test.suite()) test_suite.addTest(test_async.suite()) test_suite.addTest(test_image.suite()) + test_suite.addTest(test_qtutils.suite()) + test_suite.addTest(test_testutils.suite()) return test_suite -if __name__ == '__main__': - unittest.main(defaultTest='suite') +if __name__ == "__main__": + unittest.main(defaultTest="suite") diff --git a/silx/gui/utils/test/test.py b/silx/gui/utils/test/test.py new file mode 100644 index 0000000..8bba852 --- /dev/null +++ b/silx/gui/utils/test/test.py @@ -0,0 +1,76 @@ +# coding: utf-8 +# /*########################################################################## +# +# Copyright (c) 2019 European Synchrotron Radiation Facility +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +# ###########################################################################*/ +"""Test of functions available in silx.gui.utils module.""" + +from __future__ import absolute_import + +__authors__ = ["T. Vincent"] +__license__ = "MIT" +__date__ = "01/08/2019" + + +import unittest +from silx.gui import qt +from silx.gui.utils.testutils import TestCaseQt, SignalListener + +from silx.gui.utils import blockSignals + + +class TestBlockSignals(TestCaseQt): + """Test blockSignals context manager""" + + def _test(self, *objs): + """Test for provided objects""" + listener = SignalListener() + for obj in objs: + obj.objectNameChanged.connect(listener) + obj.setObjectName("received") + + with blockSignals(*objs): + for obj in objs: + obj.setObjectName("silent") + + self.assertEqual(listener.arguments(), [("received",)] * len(objs)) + + @unittest.skipUnless(qt.BINDING in ('PyQt5', 'PySide2'), 'Qt5 only test') + def testManyObjects(self): + """Test blockSignals with 2 QObjects""" + self._test(qt.QObject(), qt.QObject()) + + @unittest.skipUnless(qt.BINDING in ('PyQt5', 'PySide2'), 'Qt5 only test') + def testOneObject(self): + """Test blockSignals context manager with a single QObject""" + self._test(qt.QObject()) + + +def suite(): + test_suite = unittest.TestSuite() + test_suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase( + TestBlockSignals)) + return test_suite + + +if __name__ == '__main__': + unittest.main(defaultTest='suite') diff --git a/silx/gui/utils/test/test_qtutils.py b/silx/gui/utils/test/test_qtutils.py new file mode 100755 index 0000000..043a0a6 --- /dev/null +++ b/silx/gui/utils/test/test_qtutils.py @@ -0,0 +1,75 @@ +# coding: utf-8 +# /*########################################################################## +# +# Copyright (c) 2019 European Synchrotron Radiation Facility +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +# ###########################################################################*/ +"""Test of functions available in silx.gui.utils module.""" + +from __future__ import absolute_import + +__authors__ = ["T. Vincent"] +__license__ = "MIT" +__date__ = "01/08/2019" + + +import unittest +from silx.gui import qt +from silx.gui import utils +from silx.gui.utils.testutils import TestCaseQt + + +class TestQEventName(TestCaseQt): + """Test QEvent names""" + + def testNoneType(self): + result = utils.getQEventName(0) + self.assertEqual(result, "None") + + def testNoneEvent(self): + event = qt.QEvent(qt.QEvent.Type(0)) + result = utils.getQEventName(event) + self.assertEqual(result, "None") + + def testUserType(self): + result = utils.getQEventName(1050) + self.assertIn("User", result) + self.assertIn("1050", result) + + def testQtUndefinedType(self): + result = utils.getQEventName(900) + self.assertIn("Unknown", result) + self.assertIn("900", result) + + def testUndefinedType(self): + result = utils.getQEventName(70000) + self.assertIn("Unknown", result) + self.assertIn("70000", result) + + +def suite(): + test_suite = unittest.TestSuite() + test_suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(TestQEventName)) + return test_suite + + +if __name__ == "__main__": + unittest.main(defaultTest="suite") diff --git a/silx/gui/utils/test/test_testutils.py b/silx/gui/utils/test/test_testutils.py new file mode 100644 index 0000000..8a58e6e --- /dev/null +++ b/silx/gui/utils/test/test_testutils.py @@ -0,0 +1,55 @@ +# coding: utf-8 +# /*########################################################################## +# +# Copyright (c) 2017-2019 European Synchrotron Radiation Facility +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +# ###########################################################################*/ +"""Test of testutils module.""" + +__authors__ = ["T. Vincent"] +__license__ = "MIT" +__date__ = "16/01/2017" + +import unittest +import sys + +from silx.gui import qt +from ..testutils import TestCaseQt + + +class TestOutcome(unittest.TestCase): + """Tests conversion of QImage to/from numpy array.""" + + @unittest.skipIf(sys.version_info.major <= 2, 'Python3 only') + def testNoneOutcome(self): + test = TestCaseQt() + test._currentTestSucceeded() + + +def suite(): + test_suite = unittest.TestSuite() + loader = unittest.defaultTestLoader.loadTestsFromTestCase + test_suite.addTest(loader(TestOutcome)) + return test_suite + + +if __name__ == '__main__': + unittest.main(defaultTest='suite') diff --git a/silx/gui/utils/testutils.py b/silx/gui/utils/testutils.py index d7f2f41..14dcc3f 100644 --- a/silx/gui/utils/testutils.py +++ b/silx/gui/utils/testutils.py @@ -155,7 +155,8 @@ class TestCaseQt(unittest.TestCase): if hasattr(self, '_outcome'): # For Python >= 3.4 result = self.defaultTestResult() # these 2 methods have no side effects - self._feedErrorsToResult(result, self._outcome.errors) + if hasattr(self._outcome, 'errors'): + self._feedErrorsToResult(result, self._outcome.errors) else: # For Python < 3.4 result = getattr(self, '_outcomeForDoCleanups', self._resultForDoCleanups) |