pyqttoolkit 0.8.0.dev1__tar.gz → 0.8.0.post1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/PKG-INFO +5 -4
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/_version.py +3 -3
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/application/application.py +1 -1
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/config/environment.py +8 -1
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/data/__init__.py +1 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/data/interval.py +8 -11
- pyqttoolkit-0.8.0.post1/pyqttoolkit/data/message.py +29 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/datetime/qdatetime.py +1 -1
- pyqttoolkit-0.8.0.post1/pyqttoolkit/exceptions/__init__.py +18 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/logs/__init__.py +29 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/models/code_text.py +7 -3
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/models/span.py +36 -31
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/scripting/script_runner.py +14 -11
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/services/event_registry.py +1 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/services/file_dialog.py +23 -5
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/services/message_board.py +21 -19
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/services/task_runner.py +3 -4
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/bulk_value_selector.py +3 -2
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/code/code_edit.py +3 -2
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/datetime.py +7 -5
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/datetime_range_selector.py +55 -10
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/plot/legend_control.py +8 -1
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/plot/matplotlib/__init__.py +23 -23
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/plot/matplotlib/base.py +169 -56
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/plot/plot_options.py +6 -1
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/plot/plot_toolbar_options.py +2 -2
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/popup.py +3 -1
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit.egg-info/PKG-INFO +5 -4
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit.egg-info/SOURCES.txt +2 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit.egg-info/requires.txt +3 -1
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/setup.py +5 -5
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/MANIFEST.in +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/README.md +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/__init__.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/application/__init__.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/application/garbage_collector.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/colors/__init__.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/config/__init__.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/config/base.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/config/composite.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/config/default.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/config/multi_json_file.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/config/with_signal.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/config/with_value_changed.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/data/bits.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/data/cache.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/data/names.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/datetime/__init__.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/datetime/datetime.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/dependencies/__init__.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/errors/__init__.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/filesystem/__init__.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/metadata/__init__.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/metadata/dataframe_metadata_manager.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/metadata/dict_metadata_manager.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/metadata/id_generator.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/metadata/metadata_manager_base.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/models/__init__.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/models/dataframetable.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/models/dictpropertytree.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/models/dicttable.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/models/json_text.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/models/list_model.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/models/module.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/models/roles.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/models/series_data.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/models/validation.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/modules/__init__.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/modules/events/__init__.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/modules/events/add_signal.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/modules/events/module_opening.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/modules/events/rejectable.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/modules/launcher_config.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/modules/module.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/properties/__init__.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/properties/auto.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/properties/throttled.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/scripting/__init__.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/scripting/script_context.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/scripting/script_template.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/services/__init__.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/services/autosave.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/services/email.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/services/hotkey_manager.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/services/link_manager.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/services/module_service.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/services/object_converter.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/services/project_updater.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/services/theme_manager.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/services/tool_window_service.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/viewmanagers/__init__.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/viewmanagers/tool.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/__init__.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/check_box.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/code/__init__.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/code/python_syntax.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/combo_box.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/count_selector.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/default_text_line_edit.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/delegates.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/dtype_edit.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/editable_combo_box.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/file_selector.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/icon.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/icon_button.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/json_edit.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/labelled.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/layout/__init__.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/layout/collabsible.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/layout/group_box.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/layout/group_panel.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/layout/lines.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/layout/link.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/line_edit.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/linkable.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/list_view.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/main_window.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/metadata_selector.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/modulewindow.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/plot/__init__.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/plot/matplotlib/colorbar.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/plot/matplotlib/colormap.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/plot/matplotlib/font.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/plot/size.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/plot/tool_type.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/plot/toolbar.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/popout.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/property_tree.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/shrunk_push_button.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/steppable_combo_box.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/styleable.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/table.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/text_edit.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit/views/tool_window.py +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit.egg-info/dependency_links.txt +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/pyqttoolkit.egg-info/top_level.txt +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/setup.cfg +0 -0
- {pyqttoolkit-0.8.0.dev1 → pyqttoolkit-0.8.0.post1}/versioneer.py +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pyqttoolkit
|
|
3
|
-
Version: 0.8.0.
|
|
3
|
+
Version: 0.8.0.post1
|
|
4
4
|
Summary: A toolkit for PyQt 5
|
|
5
|
-
Home-page: https://github.com/
|
|
6
|
-
Author:
|
|
7
|
-
Author-email: info@
|
|
5
|
+
Home-page: https://github.com/BitBloomTech/pyqttoolkit
|
|
6
|
+
Author: Bitbloom Ltd
|
|
7
|
+
Author-email: info@bitbloom.tech
|
|
8
8
|
License: GPLv3
|
|
9
9
|
Description: # PyQtToolkit
|
|
10
10
|
|
|
@@ -13,4 +13,5 @@ Platform: any
|
|
|
13
13
|
Requires-Python: >=3.6
|
|
14
14
|
Description-Content-Type: text/markdown
|
|
15
15
|
Provides-Extra: publish
|
|
16
|
+
Provides-Extra: ui
|
|
16
17
|
Provides-Extra: test
|
|
@@ -8,11 +8,11 @@ import json
|
|
|
8
8
|
|
|
9
9
|
version_json = '''
|
|
10
10
|
{
|
|
11
|
-
"date": "
|
|
11
|
+
"date": "2025-02-10T10:45:17-0600",
|
|
12
12
|
"dirty": false,
|
|
13
13
|
"error": null,
|
|
14
|
-
"full-revisionid": "
|
|
15
|
-
"version": "0.8.0
|
|
14
|
+
"full-revisionid": "c01a30f0721570aa53de3b069854c5c25e9ebdb6",
|
|
15
|
+
"version": "0.8.0-1"
|
|
16
16
|
}
|
|
17
17
|
''' # END VERSION_JSON
|
|
18
18
|
|
|
@@ -30,7 +30,7 @@ class Application(QApplication):
|
|
|
30
30
|
def __init__(self, argv):
|
|
31
31
|
QApplication.__init__(self, argv)
|
|
32
32
|
self._dependency_container = DependencyContainer()
|
|
33
|
-
self._garbage_collector = GarbageCollector(self
|
|
33
|
+
self._garbage_collector = GarbageCollector(self)
|
|
34
34
|
|
|
35
35
|
self._module_service = None
|
|
36
36
|
self._message_board = None
|
|
@@ -15,11 +15,18 @@
|
|
|
15
15
|
# along with this program; if not, write to the Free Software Foundation,
|
|
16
16
|
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
17
17
|
import os
|
|
18
|
+
import json
|
|
18
19
|
from .base import BaseApplicationConfiguration
|
|
19
20
|
|
|
20
21
|
class EnvironmentApplicationConfiguration(BaseApplicationConfiguration):
|
|
21
22
|
def get_value(self, key):
|
|
22
|
-
|
|
23
|
+
value = os.getenv(self._format_key(key))
|
|
24
|
+
if value is None:
|
|
25
|
+
return value
|
|
26
|
+
try:
|
|
27
|
+
return json.loads(value)
|
|
28
|
+
except json.decoder.JSONDecodeError:
|
|
29
|
+
return value
|
|
23
30
|
|
|
24
31
|
def set_value(self, key, value):
|
|
25
32
|
os.environ[self._format_key(key)] = str(value)
|
|
@@ -14,16 +14,13 @@
|
|
|
14
14
|
# You should have received a copy of the GNU General Public License
|
|
15
15
|
# along with this program; if not, write to the Free Software Foundation,
|
|
16
16
|
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
17
|
+
import pandas as pd
|
|
18
|
+
|
|
17
19
|
def calculate_interval(values, sort=True):
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
if len(values) < 2:
|
|
21
|
+
return None
|
|
22
|
+
values_series = pd.Series(values)
|
|
20
23
|
if sort:
|
|
21
|
-
|
|
22
|
-
for
|
|
23
|
-
|
|
24
|
-
next_interval = value - last_value
|
|
25
|
-
if next_interval == interval:
|
|
26
|
-
return interval
|
|
27
|
-
interval = next_interval
|
|
28
|
-
last_value = value
|
|
29
|
-
return interval
|
|
24
|
+
values_series = values_series.sort_values()
|
|
25
|
+
# We want to ensure that the calculated interval is accurate for 90% of values to avoid mistakenly losing values
|
|
26
|
+
return (values_series - values_series.shift(1)).quantile(0.1)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# pyqttoolkit
|
|
2
|
+
# Copyright (C) 2018-2019, Simmovation Ltd.
|
|
3
|
+
#
|
|
4
|
+
# This program is free software; you can redistribute it and/or modify
|
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
|
6
|
+
# the Free Software Foundation; either version 3 of the License, or
|
|
7
|
+
# (at your option) any later version.
|
|
8
|
+
#
|
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
# GNU General Public License for more details.
|
|
13
|
+
#
|
|
14
|
+
# You should have received a copy of the GNU General Public License
|
|
15
|
+
# along with this program; if not, write to the Free Software Foundation,
|
|
16
|
+
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
17
|
+
from enum import Enum, IntEnum
|
|
18
|
+
|
|
19
|
+
class MessageType(Enum):
|
|
20
|
+
validation_error = 0
|
|
21
|
+
confirmation = 1
|
|
22
|
+
application_exception = 2
|
|
23
|
+
|
|
24
|
+
class MessageResponse(IntEnum):
|
|
25
|
+
ok = 1
|
|
26
|
+
cancel = 2
|
|
27
|
+
save = 4
|
|
28
|
+
discard = 8
|
|
29
|
+
ignore = 16
|
|
@@ -37,7 +37,7 @@ def pd_timestamp_to_q_datetime(pd_timestamp: datetime):
|
|
|
37
37
|
return QDateTime()
|
|
38
38
|
return QDateTime(
|
|
39
39
|
QDate(pd_timestamp.year, pd_timestamp.month, pd_timestamp.day),
|
|
40
|
-
QTime(pd_timestamp.hour, pd_timestamp.minute, pd_timestamp.second, pd_timestamp.microsecond
|
|
40
|
+
QTime(pd_timestamp.hour, pd_timestamp.minute, pd_timestamp.second, pd_timestamp.microsecond // 1000)
|
|
41
41
|
)
|
|
42
42
|
|
|
43
43
|
def step_qdatetime(control, fraction, interval, range_start, range_end):
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# pyqttoolkit
|
|
2
|
+
# Copyright (C) 2018-2019, Simmovation Ltd.
|
|
3
|
+
#
|
|
4
|
+
# This program is free software; you can redistribute it and/or modify
|
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
|
6
|
+
# the Free Software Foundation; either version 3 of the License, or
|
|
7
|
+
# (at your option) any later version.
|
|
8
|
+
#
|
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
# GNU General Public License for more details.
|
|
13
|
+
#
|
|
14
|
+
# You should have received a copy of the GNU General Public License
|
|
15
|
+
# along with this program; if not, write to the Free Software Foundation,
|
|
16
|
+
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
17
|
+
class TaskCancelled(Exception):
|
|
18
|
+
pass
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
# You should have received a copy of the GNU General Public License
|
|
15
15
|
# along with this program; if not, write to the Free Software Foundation,
|
|
16
16
|
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
17
|
+
from typing import Callable
|
|
18
|
+
from io import StringIO
|
|
17
19
|
import logging
|
|
18
20
|
from logging import handlers
|
|
19
21
|
from functools import wraps
|
|
@@ -109,3 +111,30 @@ def logf(level, log_args=True):
|
|
|
109
111
|
return result
|
|
110
112
|
return _
|
|
111
113
|
return logf_decorator
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class LogStream:
|
|
117
|
+
def __init__(self, notify_update: Callable = None):
|
|
118
|
+
self._buffer = StringIO()
|
|
119
|
+
self._notify_update = notify_update
|
|
120
|
+
|
|
121
|
+
def __iadd__(self, other):
|
|
122
|
+
self.write(other)
|
|
123
|
+
return self
|
|
124
|
+
|
|
125
|
+
def write(self, message):
|
|
126
|
+
self._buffer.write(message)
|
|
127
|
+
if self._notify_update:
|
|
128
|
+
self._notify_update()
|
|
129
|
+
|
|
130
|
+
def flush(self):
|
|
131
|
+
self._buffer.flush()
|
|
132
|
+
|
|
133
|
+
def getvalue(self):
|
|
134
|
+
return self._buffer.getvalue()
|
|
135
|
+
|
|
136
|
+
def clear(self):
|
|
137
|
+
self._buffer.close()
|
|
138
|
+
self._buffer = StringIO()
|
|
139
|
+
if self._notify_update:
|
|
140
|
+
self._notify_update()
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
from PyQt5.QtCore import QObject, pyqtSignal
|
|
18
18
|
|
|
19
19
|
from pyqttoolkit.properties import AutoProperty
|
|
20
|
+
from pyqttoolkit.logs import LogStream
|
|
20
21
|
|
|
21
22
|
class CodeTextModel(QObject):
|
|
22
23
|
def __init__(self, parent, validator):
|
|
@@ -24,16 +25,19 @@ class CodeTextModel(QObject):
|
|
|
24
25
|
self.textChanged.connect(self._validate)
|
|
25
26
|
self._validator = validator
|
|
26
27
|
self.text = ''
|
|
27
|
-
self.output =
|
|
28
|
+
self.output = LogStream(self._handle_output_buffer_changed)
|
|
28
29
|
|
|
29
30
|
textChanged = pyqtSignal(str)
|
|
30
|
-
outputChanged = pyqtSignal(
|
|
31
|
+
outputChanged = pyqtSignal(LogStream)
|
|
31
32
|
validationMessageChanged = pyqtSignal(str)
|
|
32
33
|
|
|
33
34
|
text = AutoProperty(str)
|
|
34
|
-
output = AutoProperty(
|
|
35
|
+
output = AutoProperty(LogStream)
|
|
35
36
|
validationMessage = AutoProperty(str)
|
|
36
37
|
|
|
37
38
|
def _validate(self, value):
|
|
38
39
|
validation_model = self._validator(value)
|
|
39
40
|
self.validationMessage = validation_model.error if validation_model else ''
|
|
41
|
+
|
|
42
|
+
def _handle_output_buffer_changed(self):
|
|
43
|
+
self.outputChanged.emit(self.output)
|
|
@@ -1,31 +1,36 @@
|
|
|
1
|
-
# pyqttoolkit
|
|
2
|
-
# Copyright (C) 2018-2019, Simmovation Ltd.
|
|
3
|
-
#
|
|
4
|
-
# This program is free software; you can redistribute it and/or modify
|
|
5
|
-
# it under the terms of the GNU General Public License as published by
|
|
6
|
-
# the Free Software Foundation; either version 3 of the License, or
|
|
7
|
-
# (at your option) any later version.
|
|
8
|
-
#
|
|
9
|
-
# This program is distributed in the hope that it will be useful,
|
|
10
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
-
# GNU General Public License for more details.
|
|
13
|
-
#
|
|
14
|
-
# You should have received a copy of the GNU General Public License
|
|
15
|
-
# along with this program; if not, write to the Free Software Foundation,
|
|
16
|
-
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
17
|
-
from PyQt5.QtCore import QObject
|
|
18
|
-
|
|
19
|
-
class SpanModel(QObject):
|
|
20
|
-
def __init__(self, parent, left, right):
|
|
21
|
-
QObject.__init__(self, parent)
|
|
22
|
-
self._left = left
|
|
23
|
-
self._right = right
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
1
|
+
# pyqttoolkit
|
|
2
|
+
# Copyright (C) 2018-2019, Simmovation Ltd.
|
|
3
|
+
#
|
|
4
|
+
# This program is free software; you can redistribute it and/or modify
|
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
|
6
|
+
# the Free Software Foundation; either version 3 of the License, or
|
|
7
|
+
# (at your option) any later version.
|
|
8
|
+
#
|
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
# GNU General Public License for more details.
|
|
13
|
+
#
|
|
14
|
+
# You should have received a copy of the GNU General Public License
|
|
15
|
+
# along with this program; if not, write to the Free Software Foundation,
|
|
16
|
+
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
17
|
+
from PyQt5.QtCore import QObject
|
|
18
|
+
|
|
19
|
+
class SpanModel(QObject):
|
|
20
|
+
def __init__(self, parent, left, right, radians=False):
|
|
21
|
+
QObject.__init__(self, parent)
|
|
22
|
+
self._left = left
|
|
23
|
+
self._right = right
|
|
24
|
+
self._radians = radians
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def left(self):
|
|
28
|
+
return self._left
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def right(self):
|
|
32
|
+
return self._right
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def radians(self):
|
|
36
|
+
return self._radians
|
|
@@ -80,21 +80,24 @@ class ScriptRunner:
|
|
|
80
80
|
self._context = None
|
|
81
81
|
|
|
82
82
|
def _globals(self, context):
|
|
83
|
-
return {'__builtins__': {**__builtins__, '__import__': self._import, 'exit': self._exit, **{g: self._not_implemented for g in self._disallowed_globals}}}
|
|
83
|
+
return {'__builtins__': {**__builtins__, '__import__': self._import(builtins.__import__), 'exit': self._exit, **{g: self._not_implemented for g in self._disallowed_globals}}}
|
|
84
84
|
|
|
85
85
|
def compile(self, script):
|
|
86
86
|
return compile(script, 'code', 'exec')
|
|
87
87
|
|
|
88
|
-
def _import(self,
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
88
|
+
def _import(self, import_function):
|
|
89
|
+
def _(module_name, *args, **kwargs):
|
|
90
|
+
if any(re.match(m, module_name) for m in self._disallowed_modules):
|
|
91
|
+
raise ImportError('Module not found')
|
|
92
|
+
try:
|
|
93
|
+
with add_paths(self._additional_paths):
|
|
94
|
+
module = import_function(module_name, *args, **kwargs)
|
|
95
|
+
if module_name in 'importlib':
|
|
96
|
+
module.import_module = self._import(importlib.import_module)
|
|
97
|
+
return module
|
|
98
|
+
except KeyError:
|
|
99
|
+
raise ImportError('Module not found')
|
|
100
|
+
return _
|
|
98
101
|
|
|
99
102
|
def _additional_paths(self):
|
|
100
103
|
return self._additional_paths
|
|
@@ -16,16 +16,32 @@
|
|
|
16
16
|
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
17
17
|
from os import path
|
|
18
18
|
|
|
19
|
-
from PyQt5.QtCore import QStandardPaths
|
|
19
|
+
from PyQt5.QtCore import QStandardPaths, QTimer
|
|
20
20
|
from PyQt5.QtWidgets import QFileDialog
|
|
21
21
|
|
|
22
|
+
from .event_registry import EventTypes
|
|
23
|
+
|
|
22
24
|
class FileDialogService:
|
|
23
|
-
def __init__(self, project_manager, application_configuration):
|
|
25
|
+
def __init__(self, project_manager, application_configuration, event_registry):
|
|
24
26
|
self._project_manager = project_manager
|
|
25
27
|
self._application_configuration = application_configuration
|
|
26
|
-
|
|
28
|
+
self._event_registry = event_registry
|
|
29
|
+
|
|
30
|
+
def _get_dialog(self, parent, filter_, default_directory=None):
|
|
31
|
+
dialog = QFileDialog(
|
|
32
|
+
parent,
|
|
33
|
+
directory=default_directory or self._get_default_directory(),
|
|
34
|
+
filter=filter_
|
|
35
|
+
)
|
|
36
|
+
def _notify_save_dialog_finished(result):
|
|
37
|
+
self._event_registry.event(EventTypes.save_dialog_finished).emit(result)
|
|
38
|
+
dialog.finished.connect(_notify_save_dialog_finished)
|
|
39
|
+
return dialog
|
|
40
|
+
|
|
27
41
|
def get_save_filename(self, parent, filter_, default_name=None):
|
|
28
|
-
|
|
42
|
+
default_directory = path.dirname(default_name) if default_name else None
|
|
43
|
+
dialog = self._get_dialog(parent, filter_, default_directory)
|
|
44
|
+
|
|
29
45
|
if default_name:
|
|
30
46
|
dialog.selectFile(default_name)
|
|
31
47
|
dialog.setModal(True)
|
|
@@ -35,7 +51,7 @@ class FileDialogService:
|
|
|
35
51
|
return dialog.selectedFiles()[0]
|
|
36
52
|
|
|
37
53
|
def get_open_filename(self, parent, filter_, file_mode=None):
|
|
38
|
-
dialog =
|
|
54
|
+
dialog = self._get_dialog(parent, filter_)
|
|
39
55
|
if file_mode:
|
|
40
56
|
dialog.setFileMode(file_mode)
|
|
41
57
|
if dialog.exec_():
|
|
@@ -49,5 +65,7 @@ class FileDialogService:
|
|
|
49
65
|
if default_location and path.isdir(default_location):
|
|
50
66
|
return default_location
|
|
51
67
|
return QStandardPaths.writableLocation(QStandardPaths.DocumentsLocation)
|
|
68
|
+
elif self._project_manager.filename and not path.isdir(path.dirname(self._project_manager.filename)):
|
|
69
|
+
return QStandardPaths.writableLocation(QStandardPaths.DocumentsLocation)
|
|
52
70
|
else:
|
|
53
71
|
return path.dirname(self._project_manager.filename)
|
|
@@ -14,32 +14,21 @@
|
|
|
14
14
|
# You should have received a copy of the GNU General Public License
|
|
15
15
|
# along with this program; if not, write to the Free Software Foundation,
|
|
16
16
|
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
17
|
-
from enum import Enum, IntEnum
|
|
18
17
|
|
|
19
18
|
#pylint: disable=no-name-in-module
|
|
20
|
-
from PyQt5.QtCore import QObject, pyqtSignal
|
|
19
|
+
from PyQt5.QtCore import QObject, pyqtSignal, Qt
|
|
21
20
|
#pylint: enable=no-name-in-module
|
|
22
21
|
|
|
23
22
|
from ..properties import AutoProperty
|
|
24
|
-
|
|
25
|
-
class MessageType(Enum):
|
|
26
|
-
validation_error = 0
|
|
27
|
-
confirmation = 1
|
|
28
|
-
application_exception = 2
|
|
29
|
-
|
|
30
|
-
class MessageResponse(IntEnum):
|
|
31
|
-
ok = 1
|
|
32
|
-
cancel = 2
|
|
33
|
-
save = 4
|
|
34
|
-
discard = 8
|
|
35
|
-
ignore = 16
|
|
23
|
+
from ..data import MessageType, MessageResponse
|
|
36
24
|
|
|
37
25
|
class MessageArgs:
|
|
38
|
-
def __init__(self, message_type, message, checkbox_message, response_type):
|
|
26
|
+
def __init__(self, message_type, message, checkbox_message, response_type, text_format):
|
|
39
27
|
self._message_type = message_type
|
|
40
28
|
self._message = message
|
|
41
29
|
self._checkbox_message = checkbox_message
|
|
42
30
|
self._response_type = response_type
|
|
31
|
+
self._text_format = text_format
|
|
43
32
|
self._response = None
|
|
44
33
|
self._checkbox_value = None
|
|
45
34
|
|
|
@@ -58,7 +47,11 @@ class MessageArgs:
|
|
|
58
47
|
@property
|
|
59
48
|
def response_type(self):
|
|
60
49
|
return self._response_type
|
|
61
|
-
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def text_format(self):
|
|
53
|
+
return self._text_format
|
|
54
|
+
|
|
62
55
|
@property
|
|
63
56
|
def response(self):
|
|
64
57
|
return self._response
|
|
@@ -78,9 +71,18 @@ class MessageArgs:
|
|
|
78
71
|
class MessageBoard(QObject):
|
|
79
72
|
def __init__(self, parent):
|
|
80
73
|
QObject.__init__(self, parent)
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
74
|
+
self._message_enabled = True
|
|
75
|
+
|
|
76
|
+
def messageEnabled(self):
|
|
77
|
+
return self._message_enabled
|
|
78
|
+
|
|
79
|
+
def setMessageEnabled(self, value):
|
|
80
|
+
self._message_enabled = value
|
|
81
|
+
|
|
82
|
+
def post(self, message_type, message, response_type=MessageResponse.ok, checkbox_message=None, text_format=Qt.AutoText):
|
|
83
|
+
if not self._message_enabled:
|
|
84
|
+
return
|
|
85
|
+
self.message = MessageArgs(message_type, message, checkbox_message, response_type, text_format)
|
|
84
86
|
return self.message
|
|
85
87
|
|
|
86
88
|
messageChanged = pyqtSignal(MessageArgs)
|
|
@@ -26,6 +26,7 @@ from PyQt5.QtWidgets import QApplication
|
|
|
26
26
|
from concurrent.futures import ThreadPoolExecutor
|
|
27
27
|
|
|
28
28
|
from ..properties import AutoProperty
|
|
29
|
+
from ..exceptions import TaskCancelled
|
|
29
30
|
|
|
30
31
|
LOGGER = logging.getLogger(__name__)
|
|
31
32
|
|
|
@@ -71,8 +72,6 @@ class BusyArgs(QObject):
|
|
|
71
72
|
if self._cancellable:
|
|
72
73
|
self.cancelled.emit()
|
|
73
74
|
|
|
74
|
-
class TaskCancelled(Exception):
|
|
75
|
-
pass
|
|
76
75
|
|
|
77
76
|
class Worker:
|
|
78
77
|
def __init__(self, task_runner, f, args, busy_args, on_completed, on_cancelled, on_error, error_description):
|
|
@@ -178,7 +177,7 @@ class TaskRunner(QObject):
|
|
|
178
177
|
self._is_cancelled = False
|
|
179
178
|
self._executor = ThreadPoolExecutor(max_workers=1, thread_name_prefix='TaskRunner_Thread')
|
|
180
179
|
|
|
181
|
-
def run_task(self, task_function, task_args=None, on_completed=None, on_cancelled=None, on_error=None, description=None, error_description=None, show_progress=True, cancellable=False, **kwargs):
|
|
180
|
+
def run_task(self, task_function, task_args=None, on_completed=None, on_cancelled=None, on_error=None, description=None, error_description=None, show_progress=True, cancellable=False, force_indeterminate_start=False, **kwargs):
|
|
182
181
|
"""function::runTask(self, task_function, task_args, on_completed, on_error)
|
|
183
182
|
:param task_function: The function to execute
|
|
184
183
|
:param task_args: The arguments to pass to the function
|
|
@@ -194,7 +193,7 @@ class TaskRunner(QObject):
|
|
|
194
193
|
|
|
195
194
|
if 'update_progress' in parameters:
|
|
196
195
|
kwargs['update_progress'] = self.update_progress
|
|
197
|
-
indeterminate =
|
|
196
|
+
indeterminate = force_indeterminate_start
|
|
198
197
|
else:
|
|
199
198
|
indeterminate = True
|
|
200
199
|
|
|
@@ -69,8 +69,9 @@ class BulkValueSelectorWidget(QWidget):
|
|
|
69
69
|
@auto_property(list)
|
|
70
70
|
def selectedValues(self):
|
|
71
71
|
if isinstance(self._value_selector.model(), QStringListModel):
|
|
72
|
+
string_list = self._value_selector.model().stringList()
|
|
72
73
|
return [
|
|
73
|
-
|
|
74
|
+
string_list[i.row()]\
|
|
74
75
|
for i in self._value_selector.selectedIndexes() if i.row() < self._value_selector.model().rowCount()
|
|
75
76
|
]
|
|
76
77
|
return [self._value_selector.model().data(i, DataRole) for i in self._value_selector.selectedIndexes() if i.row() < self._value_selector.model().rowCount()]
|
|
@@ -82,7 +83,7 @@ class BulkValueSelectorWidget(QWidget):
|
|
|
82
83
|
else self._select_values if self._value_selector.model()
|
|
83
84
|
else None
|
|
84
85
|
)
|
|
85
|
-
if select_values:
|
|
86
|
+
if select_values and values != self.selectedValues:
|
|
86
87
|
signals_blocked = self.blockSignals(True)
|
|
87
88
|
self._value_selector.clearSelection()
|
|
88
89
|
select_values(values)
|
|
@@ -115,7 +115,7 @@ class CodeTextEdit(QPlainTextEdit):
|
|
|
115
115
|
if block.isVisible() and bottom >= event.rect().top():
|
|
116
116
|
number = str(block_number + 1)
|
|
117
117
|
painter.setPen(Qt.black)
|
|
118
|
-
painter.drawText(0, top, self._line_number_area.width(), self.fontMetrics().height(), Qt.AlignRight, number)
|
|
118
|
+
painter.drawText(0, int(top), self._line_number_area.width(), self.fontMetrics().height(), Qt.AlignRight, number)
|
|
119
119
|
block = block.next()
|
|
120
120
|
top = bottom
|
|
121
121
|
bottom = top + self.blockBoundingRect(block).height()
|
|
@@ -194,7 +194,7 @@ class CodeEdit(QWidget):
|
|
|
194
194
|
self._text_edit.setPlainText(model.text)
|
|
195
195
|
model.textChanged.connect(self._set_text(self._text_edit))
|
|
196
196
|
if hasattr(model, 'output'):
|
|
197
|
-
self._output_pane.setPlainText(model.output)
|
|
197
|
+
self._output_pane.setPlainText(model.output.getvalue())
|
|
198
198
|
model.outputChanged.connect(self._set_text(self._output_pane, True))
|
|
199
199
|
self._output_pane.setVisible(True)
|
|
200
200
|
else:
|
|
@@ -207,6 +207,7 @@ class CodeEdit(QWidget):
|
|
|
207
207
|
def _(text):
|
|
208
208
|
widget_inst = widget_ref()
|
|
209
209
|
if widget_inst:
|
|
210
|
+
text = text if isinstance(text, str) else text.getvalue()
|
|
210
211
|
if widget_inst.toPlainText() != text:
|
|
211
212
|
widget_inst.setPlainText(text)
|
|
212
213
|
if scroll_to_end:
|
|
@@ -40,7 +40,7 @@ class DateTimeEdit(QDateTimeEdit):
|
|
|
40
40
|
self.isLimit = False
|
|
41
41
|
self._default = default
|
|
42
42
|
self.isLimitChanged.connect(self._handle_is_limit_changed)
|
|
43
|
-
self.
|
|
43
|
+
self.editingFinished.connect(self._handle_date_time_editing_finished)
|
|
44
44
|
self.setCalendarPopup(calendar_popup)
|
|
45
45
|
if calendar_popup:
|
|
46
46
|
self.calendarWidget().clicked.connect(self._handle_date_changed_from_calendar)
|
|
@@ -50,7 +50,7 @@ class DateTimeEdit(QDateTimeEdit):
|
|
|
50
50
|
|
|
51
51
|
isLimit = AutoProperty(bool)
|
|
52
52
|
|
|
53
|
-
def focusOutEvent(self, event):
|
|
53
|
+
def focusOutEvent(self, event=None):
|
|
54
54
|
if self._start_date and self.dateTime() < self._start_date:
|
|
55
55
|
self.setDateTime(self._start_date)
|
|
56
56
|
elif self._min_date and self.dateTime() < self._min_date:
|
|
@@ -59,7 +59,7 @@ class DateTimeEdit(QDateTimeEdit):
|
|
|
59
59
|
self.setDateTime(self._end_date)
|
|
60
60
|
elif self._max_date and self.dateTime() > self._max_date:
|
|
61
61
|
self.setDateTime(self._max_date)
|
|
62
|
-
return QDateTimeEdit.focusOutEvent(self, event)
|
|
62
|
+
return event and QDateTimeEdit.focusOutEvent(self, event)
|
|
63
63
|
|
|
64
64
|
def setDateTimeRange(self, start_date, end_date):
|
|
65
65
|
self._start_date = start_date
|
|
@@ -95,13 +95,15 @@ class DateTimeEdit(QDateTimeEdit):
|
|
|
95
95
|
self.value = QDateTime()
|
|
96
96
|
|
|
97
97
|
def _handle_is_limit_changed(self, is_limit):
|
|
98
|
-
stylesheet = 'DateTimeEdit {font: italic}' if is_limit else ''
|
|
98
|
+
stylesheet = 'DateTimeEdit {font: italic}' if is_limit else 'DateTimeEdit {font: normal}'
|
|
99
99
|
self.setStyleSheet(stylesheet)
|
|
100
100
|
|
|
101
|
-
def
|
|
101
|
+
def _handle_date_time_editing_finished(self):
|
|
102
|
+
value = self.dateTime()
|
|
102
103
|
if value is not None or (isinstance(value, QDateTime) and value.isValid()):
|
|
103
104
|
self.isLimit = False
|
|
104
105
|
self.valueChanged.emit(self.value)
|
|
106
|
+
self.focusOutEvent()
|
|
105
107
|
|
|
106
108
|
def _handle_date_changed_from_calendar(self, value):
|
|
107
109
|
self.value = QDateTime(value, QTime(0, 0))
|