pyqttoolkit 0.9.1__py3-none-any.whl

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.
Files changed (133) hide show
  1. pyqttoolkit/__init__.py +20 -0
  2. pyqttoolkit/_version.py +21 -0
  3. pyqttoolkit/application/__init__.py +18 -0
  4. pyqttoolkit/application/application.py +86 -0
  5. pyqttoolkit/application/garbage_collector.py +65 -0
  6. pyqttoolkit/colors/__init__.py +84 -0
  7. pyqttoolkit/config/__init__.py +20 -0
  8. pyqttoolkit/config/base.py +22 -0
  9. pyqttoolkit/config/composite.py +31 -0
  10. pyqttoolkit/config/default.py +27 -0
  11. pyqttoolkit/config/environment.py +35 -0
  12. pyqttoolkit/config/multi_json_file.py +93 -0
  13. pyqttoolkit/config/with_signal.py +30 -0
  14. pyqttoolkit/config/with_value_changed.py +31 -0
  15. pyqttoolkit/data/__init__.py +21 -0
  16. pyqttoolkit/data/bits.py +23 -0
  17. pyqttoolkit/data/cache.py +64 -0
  18. pyqttoolkit/data/interval.py +26 -0
  19. pyqttoolkit/data/message.py +29 -0
  20. pyqttoolkit/data/names.py +24 -0
  21. pyqttoolkit/datetime/__init__.py +16 -0
  22. pyqttoolkit/datetime/datetime.py +51 -0
  23. pyqttoolkit/datetime/qdatetime.py +53 -0
  24. pyqttoolkit/dependencies/__init__.py +56 -0
  25. pyqttoolkit/errors/__init__.py +19 -0
  26. pyqttoolkit/exceptions/__init__.py +18 -0
  27. pyqttoolkit/filesystem/__init__.py +24 -0
  28. pyqttoolkit/logs/__init__.py +140 -0
  29. pyqttoolkit/metadata/__init__.py +23 -0
  30. pyqttoolkit/metadata/dataframe_metadata_manager.py +105 -0
  31. pyqttoolkit/metadata/dict_metadata_manager.py +63 -0
  32. pyqttoolkit/metadata/id_generator.py +20 -0
  33. pyqttoolkit/metadata/metadata_manager_base.py +54 -0
  34. pyqttoolkit/models/__init__.py +26 -0
  35. pyqttoolkit/models/code_text.py +43 -0
  36. pyqttoolkit/models/dataframetable.py +135 -0
  37. pyqttoolkit/models/dictpropertytree.py +155 -0
  38. pyqttoolkit/models/dicttable.py +140 -0
  39. pyqttoolkit/models/json_text.py +52 -0
  40. pyqttoolkit/models/list_model.py +52 -0
  41. pyqttoolkit/models/module.py +26 -0
  42. pyqttoolkit/models/roles.py +23 -0
  43. pyqttoolkit/models/series_data.py +68 -0
  44. pyqttoolkit/models/span.py +36 -0
  45. pyqttoolkit/models/validation.py +27 -0
  46. pyqttoolkit/modules/__init__.py +18 -0
  47. pyqttoolkit/modules/events/__init__.py +19 -0
  48. pyqttoolkit/modules/events/add_signal.py +31 -0
  49. pyqttoolkit/modules/events/module_opening.py +21 -0
  50. pyqttoolkit/modules/events/rejectable.py +29 -0
  51. pyqttoolkit/modules/launcher_config.py +55 -0
  52. pyqttoolkit/modules/module.py +111 -0
  53. pyqttoolkit/properties/__init__.py +18 -0
  54. pyqttoolkit/properties/auto.py +221 -0
  55. pyqttoolkit/properties/throttled.py +77 -0
  56. pyqttoolkit/scripting/__init__.py +19 -0
  57. pyqttoolkit/scripting/script_context.py +36 -0
  58. pyqttoolkit/scripting/script_runner.py +132 -0
  59. pyqttoolkit/scripting/script_template.py +42 -0
  60. pyqttoolkit/services/__init__.py +32 -0
  61. pyqttoolkit/services/autosave.py +41 -0
  62. pyqttoolkit/services/email.py +25 -0
  63. pyqttoolkit/services/event_registry.py +52 -0
  64. pyqttoolkit/services/file_dialog.py +71 -0
  65. pyqttoolkit/services/hotkey_manager.py +137 -0
  66. pyqttoolkit/services/link_manager.py +135 -0
  67. pyqttoolkit/services/message_board.py +90 -0
  68. pyqttoolkit/services/module_service.py +154 -0
  69. pyqttoolkit/services/object_converter.py +45 -0
  70. pyqttoolkit/services/project_updater.py +149 -0
  71. pyqttoolkit/services/task_runner.py +281 -0
  72. pyqttoolkit/services/theme_manager.py +46 -0
  73. pyqttoolkit/services/tool_window_service.py +46 -0
  74. pyqttoolkit/viewmanagers/__init__.py +17 -0
  75. pyqttoolkit/viewmanagers/tool.py +23 -0
  76. pyqttoolkit/views/__init__.py +50 -0
  77. pyqttoolkit/views/bulk_value_selector.py +112 -0
  78. pyqttoolkit/views/check_box.py +36 -0
  79. pyqttoolkit/views/code/__init__.py +18 -0
  80. pyqttoolkit/views/code/code_edit.py +268 -0
  81. pyqttoolkit/views/code/python_syntax.py +226 -0
  82. pyqttoolkit/views/combo_box.py +101 -0
  83. pyqttoolkit/views/count_selector.py +59 -0
  84. pyqttoolkit/views/datetime.py +111 -0
  85. pyqttoolkit/views/datetime_range_selector.py +231 -0
  86. pyqttoolkit/views/default_text_line_edit.py +50 -0
  87. pyqttoolkit/views/delegates.py +117 -0
  88. pyqttoolkit/views/dtype_edit.py +117 -0
  89. pyqttoolkit/views/editable_combo_box.py +45 -0
  90. pyqttoolkit/views/file_selector.py +51 -0
  91. pyqttoolkit/views/icon.py +67 -0
  92. pyqttoolkit/views/icon_button.py +129 -0
  93. pyqttoolkit/views/json_edit.py +21 -0
  94. pyqttoolkit/views/labelled.py +29 -0
  95. pyqttoolkit/views/layout/__init__.py +21 -0
  96. pyqttoolkit/views/layout/collabsible.py +59 -0
  97. pyqttoolkit/views/layout/group_box.py +48 -0
  98. pyqttoolkit/views/layout/group_panel.py +188 -0
  99. pyqttoolkit/views/layout/lines.py +30 -0
  100. pyqttoolkit/views/layout/link.py +38 -0
  101. pyqttoolkit/views/line_edit.py +61 -0
  102. pyqttoolkit/views/linkable.py +49 -0
  103. pyqttoolkit/views/list_view.py +43 -0
  104. pyqttoolkit/views/main_window.py +91 -0
  105. pyqttoolkit/views/metadata_selector.py +84 -0
  106. pyqttoolkit/views/modulewindow.py +81 -0
  107. pyqttoolkit/views/plot/__init__.py +26 -0
  108. pyqttoolkit/views/plot/legend_control.py +121 -0
  109. pyqttoolkit/views/plot/matplotlib/__init__.py +23 -0
  110. pyqttoolkit/views/plot/matplotlib/base.py +1056 -0
  111. pyqttoolkit/views/plot/matplotlib/colorbar.py +75 -0
  112. pyqttoolkit/views/plot/matplotlib/colormap.py +48 -0
  113. pyqttoolkit/views/plot/matplotlib/font.py +55 -0
  114. pyqttoolkit/views/plot/plot_options.py +211 -0
  115. pyqttoolkit/views/plot/plot_toolbar_options.py +133 -0
  116. pyqttoolkit/views/plot/size.py +41 -0
  117. pyqttoolkit/views/plot/tool_type.py +26 -0
  118. pyqttoolkit/views/plot/toolbar.py +100 -0
  119. pyqttoolkit/views/popout.py +41 -0
  120. pyqttoolkit/views/popup.py +41 -0
  121. pyqttoolkit/views/property_tree.py +26 -0
  122. pyqttoolkit/views/shrunk_push_button.py +34 -0
  123. pyqttoolkit/views/steppable_combo_box.py +67 -0
  124. pyqttoolkit/views/styleable.py +37 -0
  125. pyqttoolkit/views/table.py +146 -0
  126. pyqttoolkit/views/text_edit.py +31 -0
  127. pyqttoolkit/views/tool_window.py +35 -0
  128. pyqttoolkit-0.9.1.dist-info/METADATA +69 -0
  129. pyqttoolkit-0.9.1.dist-info/RECORD +133 -0
  130. pyqttoolkit-0.9.1.dist-info/WHEEL +5 -0
  131. pyqttoolkit-0.9.1.dist-info/licenses/LICENSE.txt +674 -0
  132. pyqttoolkit-0.9.1.dist-info/licenses/LICENSE_SHORT +16 -0
  133. pyqttoolkit-0.9.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,101 @@
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
+ """:mod:`combo_box`
18
+ Defines the ComboBox class
19
+ """
20
+ from enum import Enum
21
+
22
+ from PyQt5.QtWidgets import QComboBox
23
+ from PyQt5.QtCore import Qt, pyqtSignal
24
+
25
+ from pyqttoolkit.properties import AutoProperty
26
+ from pyqttoolkit.models.roles import DataRole
27
+ from pyqttoolkit.views.styleable import make_styleable
28
+
29
+ class ComboBox(QComboBox):
30
+ def __init__(self, parent, padding=20):
31
+ QComboBox.__init__(self, parent)
32
+ self.setMaxVisibleItems(20)
33
+ self.setMinimumWidth(50)
34
+ self.setSizeAdjustPolicy(QComboBox.AdjustToContents)
35
+ self.view().setTextElideMode(Qt.ElideNone)
36
+ self._padding = padding
37
+
38
+ def setModel(self, value):
39
+ QComboBox.setModel(self, value)
40
+ self._update_minimum_width()
41
+ value.dataChanged.connect(self._update_minimum_width)
42
+
43
+ def _update_minimum_width(self):
44
+ width = self.minimumWidth()
45
+ if self.model():
46
+ for i in range(self.model().rowCount()):
47
+ index = self.model().createIndex(i, 0)
48
+ display_text = self.model().data(index, Qt.DisplayRole)
49
+ width = max(width, self.fontMetrics().width(display_text))
50
+ self.view().setMinimumWidth(width + self._padding)
51
+
52
+ ComboBox = make_styleable(ComboBox)
53
+
54
+ def typed_bindable_combo_box(type_):
55
+ class TypedBindableComboBox(ComboBox):
56
+ def __init__(self, parent):
57
+ ComboBox.__init__(self, parent)
58
+
59
+ self.currentIndexChanged.connect(self._handle_index_changed)
60
+ self.valueChanged.connect(self._update_index)
61
+
62
+ valueChanged = pyqtSignal(type_)
63
+
64
+ value = AutoProperty(type_)
65
+
66
+ def setModel(self, value):
67
+ super().setModel(value)
68
+ if hasattr(value, 'dataChanged'):
69
+ value.dataChanged.connect(self._handle_data_changed)
70
+
71
+ def _handle_data_changed(self):
72
+ self._update_index(self.value)
73
+ self._handle_index_changed(self.currentIndex())
74
+
75
+ def _handle_index_changed(self, index):
76
+ if 0 <= index < self.model().rowCount():
77
+ model_index = self.model().createIndex(index, 0)
78
+ self.value = self._get_data_value(model_index)
79
+
80
+ def _update_index(self, value):
81
+ index = self._get_index(value)
82
+ index = index if index is not None else -1
83
+ if -1 <= index < self.model().rowCount():
84
+ self.setCurrentIndex(index)
85
+
86
+
87
+ def _get_index(self, value):
88
+ for i in range(self.model().rowCount()):
89
+ model_index = self.model().createIndex(i, 0)
90
+ if self._get_data_value(model_index) == value:
91
+ return i
92
+ return None
93
+
94
+ def _get_data_value(self, model_index):
95
+ value = self.model().data(model_index, DataRole)
96
+ value = value if value is not None else self.model().data(model_index, Qt.DisplayRole)
97
+ return value if not isinstance(value, Enum) else value.name
98
+
99
+ return make_styleable(TypedBindableComboBox)
100
+
101
+ BindableComboBox = typed_bindable_combo_box(str)
@@ -0,0 +1,59 @@
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 pyqtSignal, Qt
18
+ from PyQt5.QtWidgets import QWidget, QHBoxLayout, QScrollBar, QLineEdit
19
+ from PyQt5.QtGui import QIntValidator
20
+
21
+ class CountSelectorWidget(QWidget):
22
+ def __init__(self, parent, minimum, maximum, initial=0):
23
+ QWidget.__init__(self, parent)
24
+
25
+ self._slider = QScrollBar(Qt.Horizontal, self)
26
+ self._slider.setMinimum(minimum)
27
+ self._slider.setMaximum(maximum)
28
+ self._slider.setSingleStep(1)
29
+ # self._slider.setTickInterval(1)
30
+
31
+ self._linedit = QLineEdit(self)
32
+ self._linedit.setValidator(QIntValidator(minimum, maximum, self))
33
+ self._linedit.setMinimumWidth(20)
34
+
35
+ self._layout = QHBoxLayout(self)
36
+ self._layout.setContentsMargins(0, 0, 0, 0)
37
+ self._layout.addWidget(self._slider, 4)
38
+ self._layout.addWidget(self._linedit, 1)
39
+
40
+ self._slider.valueChanged.connect(self._update_value)
41
+ self._linedit.textChanged.connect(self._update_value)
42
+ self._update_value(initial)
43
+
44
+ valueChanged = pyqtSignal(int)
45
+
46
+ def _update_value(self, value):
47
+ value = int(value) if value else 0
48
+ self.value = value
49
+ self.valueChanged.emit(value)
50
+
51
+ @property
52
+ def value(self):
53
+ return self._slider.value()
54
+
55
+ @value.setter
56
+ def value(self, value):
57
+ if self._slider.value() != value:
58
+ self._slider.setValue(value)
59
+ self._linedit.setText(str(value))
@@ -0,0 +1,111 @@
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
+ """:mod:`datetime`
18
+ Defines the DateTimeEdit class
19
+ """
20
+ from enum import Enum
21
+
22
+ from PyQt5.QtCore import QDateTime, QTime, pyqtSignal
23
+ from PyQt5.QtWidgets import QDateTimeEdit
24
+
25
+ from pyqttoolkit.properties import auto_property, AutoProperty
26
+
27
+ from .styleable import make_styleable
28
+
29
+ class DateTimeEdit(QDateTimeEdit):
30
+ class Limit(Enum):
31
+ min = 0
32
+ max = 1
33
+
34
+ def __init__(self, parent, default=Limit.min, calendar_popup=True):
35
+ QDateTimeEdit.__init__(self, parent)
36
+ self.setDisplayFormat('dd-MMM-yyyy hh:mm')
37
+ self.setButtonSymbols(QDateTimeEdit.NoButtons)
38
+ self._min_date = self._max_date = None
39
+ self._start_date = self._end_date = None
40
+ self.isLimit = False
41
+ self._default = default
42
+ self.isLimitChanged.connect(self._handle_is_limit_changed)
43
+ self.editingFinished.connect(self._handle_date_time_editing_finished)
44
+ self.setCalendarPopup(calendar_popup)
45
+ if calendar_popup:
46
+ self.calendarWidget().clicked.connect(self._handle_date_changed_from_calendar)
47
+
48
+ valueChanged = pyqtSignal(QDateTime)
49
+ isLimitChanged = pyqtSignal(bool)
50
+
51
+ isLimit = AutoProperty(bool)
52
+
53
+ def focusOutEvent(self, event=None):
54
+ if self._start_date and self.dateTime() < self._start_date:
55
+ self.setDateTime(self._start_date)
56
+ elif self._min_date and self.dateTime() < self._min_date:
57
+ self.setDateTime(self._min_date)
58
+ elif self._end_date and self.dateTime() > self._end_date:
59
+ self.setDateTime(self._end_date)
60
+ elif self._max_date and self.dateTime() > self._max_date:
61
+ self.setDateTime(self._max_date)
62
+ return event and QDateTimeEdit.focusOutEvent(self, event)
63
+
64
+ def setDateTimeRange(self, start_date, end_date):
65
+ self._start_date = start_date
66
+ self._end_date = end_date
67
+
68
+ def setMinimumDateTime(self, min_date):
69
+ self._min_date = min_date
70
+ super().setMinimumDateTime(min_date)
71
+
72
+ def setMaximumDateTime(self, max_date):
73
+ self._max_date = max_date
74
+ super().setMaximumDateTime(max_date)
75
+
76
+ @auto_property(QDateTime)
77
+ def value(self):
78
+ return QDateTime() if self.isLimit else self.dateTime()
79
+
80
+ @value.setter
81
+ def value(self, value):
82
+ value = value or QDateTime()
83
+ if not value.isValid() and self._start_date is not None and self._end_date is not None:
84
+ date_time = self._start_date if self._default == self.Limit.min else self._end_date
85
+ is_limit = True
86
+ else:
87
+ date_time = value
88
+ is_limit = False
89
+ if self.dateTime() != date_time:
90
+ self.setDateTime(date_time)
91
+ self.isLimit = is_limit
92
+ self.valueChanged.emit(value)
93
+
94
+ def reset(self):
95
+ self.value = QDateTime()
96
+
97
+ def _handle_is_limit_changed(self, is_limit):
98
+ stylesheet = 'DateTimeEdit {font: italic}' if is_limit else 'DateTimeEdit {font: normal}'
99
+ self.setStyleSheet(stylesheet)
100
+
101
+ def _handle_date_time_editing_finished(self):
102
+ value = self.dateTime()
103
+ if value is not None or (isinstance(value, QDateTime) and value.isValid()):
104
+ self.isLimit = False
105
+ self.valueChanged.emit(self.value)
106
+ self.focusOutEvent()
107
+
108
+ def _handle_date_changed_from_calendar(self, value):
109
+ self.value = QDateTime(value, QTime(0, 0))
110
+
111
+ DateTimeEdit = make_styleable(DateTimeEdit)
@@ -0,0 +1,231 @@
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
+ """:mod:`datetime_range_selector`
18
+ Defines the DatetimeRangeSelectorWidget
19
+ """
20
+ import weakref
21
+
22
+ from PyQt5.QtCore import pyqtSignal, QDateTime, QSize
23
+ from PyQt5.QtWidgets import QGridLayout, QSizePolicy, QMenu, QAction, QPushButton
24
+
25
+ from datetime import timedelta, datetime
26
+ from typing import Optional, Tuple
27
+
28
+ from pyqttoolkit.properties import auto_property, bind, unbind
29
+ from pyqttoolkit.datetime.qdatetime import step_qdatetime
30
+ from pyqttoolkit.services.link_manager import IncompatibleWidgets
31
+ from .linkable import LinkableWidget
32
+ from .datetime import DateTimeEdit
33
+ from .icon_button import IconButton
34
+
35
+ class DatetimeRangeSelectorWidget(LinkableWidget):
36
+ """class::DatetimeRangeSelectorWidget
37
+ Widget to select a datetime range
38
+ """
39
+ def __init__(self, parent, paging=False, link_manager=None, reset_enabled=True, link_type=None,
40
+ update_limits_on_value_change: bool = True,
41
+ default_limits: Optional[Tuple[datetime, datetime]]=None,
42
+ set_to_limit_buttons: bool = False):
43
+ LinkableWidget.__init__(self, parent, link_manager, link_type)
44
+ self._date_range_start = self._date_range_end = None
45
+ self._interval = None
46
+ self._update_limits_on_value_change = update_limits_on_value_change
47
+
48
+ if paging:
49
+ self._back_one = IconButton('left.svg', self.tr('Scroll Left'), self, QSize(8, 30))
50
+ self._back_one.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding)
51
+ self._back_one.clicked.connect(self._step(-1))
52
+ self._from_selector = DateTimeEdit(self, DateTimeEdit.Limit.min)
53
+ self._to_selector = DateTimeEdit(self, DateTimeEdit.Limit.max)
54
+ if default_limits:
55
+ self._from_selector.setDateTimeRange(*default_limits)
56
+ self._to_selector.setDateTimeRange(*default_limits)
57
+ if paging:
58
+ self._forward_one = IconButton('right.svg', self.tr('Scroll Right'), self, QSize(8, 30))
59
+ self._forward_one.clicked.connect(self._step(1))
60
+ self._forward_one.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding)
61
+
62
+ self._layout = QGridLayout(self)
63
+ self._layout.setContentsMargins(0, 0, 0, 0)
64
+ self._layout.addWidget(self._from_selector, 0, 1)
65
+ self._layout.addWidget(self._to_selector, 1, 1)
66
+
67
+ if paging:
68
+ self._layout.addWidget(self._back_one, 0, 0, 2, 1)
69
+ self._layout.addWidget(self._forward_one, 0, 2, 2, 1)
70
+
71
+ if set_to_limit_buttons:
72
+ self._set_to_start = QPushButton(self.tr('Set to Start'), self)
73
+ self._set_to_start.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
74
+ self._set_to_start.setFixedWidth(65)
75
+ self._set_to_end = QPushButton(self.tr('Set to End'), self)
76
+ self._set_to_end.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
77
+ self._set_to_end.setFixedWidth(65)
78
+
79
+ self._layout.addWidget(self._set_to_start, 0, 2)
80
+ self._layout.addWidget(self._set_to_end, 1, 2)
81
+
82
+ def _handle_set_to_limit_clicked(widget, prop):
83
+ view_ref = weakref.ref(self)
84
+ def _():
85
+ view = view_ref()
86
+ if view:
87
+ widget.reset()
88
+ prop.__get__(view).emit(widget.value)
89
+ return _
90
+
91
+ self._set_to_start.clicked.connect(
92
+ _handle_set_to_limit_clicked(
93
+ self._from_selector, DatetimeRangeSelectorWidget.dateFromChanged))
94
+ self._set_to_end.clicked.connect(
95
+ _handle_set_to_limit_clicked(
96
+ self._to_selector, DatetimeRangeSelectorWidget.dateToChanged))
97
+
98
+ self._from_selector.editingFinished.connect(self._date_from_editing_finished)
99
+ self._to_selector.editingFinished.connect(self._date_to_editing_finished)
100
+
101
+ self._menu = QMenu(self)
102
+ self._reset = QAction(self.tr('Reset'), self)
103
+ self._reset.triggered.connect(self._handle_reset)
104
+ self._menu.addAction(self._reset)
105
+ self._reset_enabled = reset_enabled
106
+
107
+ dateFromChanged = pyqtSignal(QDateTime)
108
+ dateToChanged = pyqtSignal(QDateTime)
109
+ datesChanged = pyqtSignal(QDateTime, QDateTime)
110
+
111
+ @property
112
+ def date_from_selector(self):
113
+ return self._from_selector
114
+
115
+ @property
116
+ def date_to_selector(self):
117
+ return self._to_selector
118
+
119
+ def contextMenuEvent(self, event):
120
+ if self._reset_enabled:
121
+ self._menu.exec_(event.globalPos())
122
+
123
+ def _handle_reset(self):
124
+ self.setDates(self._date_range_start, self._date_range_end)
125
+
126
+ def link(self, other):
127
+ if not isinstance(other, DatetimeRangeSelectorWidget):
128
+ raise IncompatibleWidgets()
129
+ bind(self, other, 'dateFrom')
130
+ bind(self, other, 'dateTo')
131
+ self.datesChanged.connect(other.setDates)
132
+ other.datesChanged.connect(self.setDates)
133
+
134
+ def unlink(self, other):
135
+ unbind(self, other, 'dateFrom')
136
+ unbind(self, other, 'dateTo')
137
+ self.datesChanged.disconnect(other.setDates)
138
+ other.datesChanged.disconnect(self.setDates)
139
+
140
+ def setDates(self, dateFrom, dateTo):
141
+ if self.dateFrom != dateFrom or self.dateTo != dateTo:
142
+ signals_blocked = self.blockSignals(True)
143
+ self.dateFrom = dateFrom
144
+ self.dateTo = dateTo
145
+ self.blockSignals(signals_blocked)
146
+ self.datesChanged.emit(dateFrom, dateTo)
147
+
148
+ def setDateRange(self, start_date, end_date):
149
+ """function::setDateRange(self, start_data, end_date)
150
+ Set the date range for this widget
151
+ """
152
+ self._from_selector.setDateTimeRange(start_date, end_date)
153
+ self._to_selector.setDateTimeRange(start_date, end_date)
154
+ self._date_range_start = start_date
155
+ self._date_range_end = end_date
156
+
157
+ def setInterval(self, interval):
158
+ self._interval = interval
159
+
160
+ if interval < timedelta(seconds=1):
161
+ display_format = 'dd-MMM-yyyy hh:mm:ss.zz'
162
+ elif interval < timedelta(minutes=1):
163
+ display_format = 'dd-MMM-yyyy hh:mm:ss'
164
+ else:
165
+ display_format = 'dd-MMM-yyyy hh:mm'
166
+
167
+ for selector in self._from_selector, self._to_selector:
168
+ selector.setDisplayFormat(display_format)
169
+
170
+ @auto_property(QDateTime)
171
+ def dateFrom(self):
172
+ """function::dateFrom(self)
173
+ Auto property accessor for dateFrom
174
+ """
175
+ return self._from_selector.dateTime()
176
+
177
+ @dateFrom.setter
178
+ def dateFrom(self, value):
179
+ """function::dateFrom(self, value)
180
+ Auto property setter for dateFrom
181
+ """
182
+ value = value or QDateTime()
183
+ if self._from_selector.dateTime() != value:
184
+ self._from_selector.setDateTime(value)
185
+ self.dateFromChanged.emit(value)
186
+
187
+ @auto_property(QDateTime)
188
+ def dateTo(self):
189
+ """function::dateTo(self)
190
+ Auto property accessor for dateTo
191
+ """
192
+ return self._to_selector.dateTime()
193
+
194
+ @dateTo.setter
195
+ def dateTo(self, value):
196
+ """function::dateTo(self, value)
197
+ Auto property setter for dateTo
198
+ """
199
+ value = value or QDateTime()
200
+ if self._to_selector.dateTime() != value:
201
+ self._to_selector.setDateTime(value)
202
+ self.dateToChanged.emit(value)
203
+
204
+ def sizeHint(self):
205
+ """function::sizeHint(self)
206
+ Override the QWidget.sizeHint method to provide a size hint
207
+ """
208
+ return self._layout.sizeHint()
209
+
210
+ def _date_from_editing_finished(self):
211
+ value = self._from_selector.dateTime()
212
+ if self._update_limits_on_value_change:
213
+ self._to_selector.setMinimumDateTime(value)
214
+ self.dateFromChanged.emit(value)
215
+
216
+ def _date_to_editing_finished(self):
217
+ value = self._to_selector.dateTime()
218
+ if self._update_limits_on_value_change:
219
+ self._from_selector.setMaximumDateTime(value)
220
+ self.dateToChanged.emit(value)
221
+
222
+ def _step(self, fraction):
223
+ def _():
224
+ signals_blocked = self.blockSignals(True)
225
+ step_qdatetime(self, fraction, self._interval, self._date_range_start, self._date_range_end)
226
+ self.blockSignals(signals_blocked)
227
+ self.datesChanged.emit(self.dateFrom, self.dateTo)
228
+ return _
229
+
230
+ def step(self, fraction):
231
+ return self._step(fraction)()
@@ -0,0 +1,50 @@
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 pyqtSignal
18
+ #pylint: enable=no-name-in-module
19
+
20
+ from pyqttoolkit.properties import AutoProperty
21
+ from pyqttoolkit.views import LineEdit
22
+
23
+ class DefaultTextLineEdit(LineEdit):
24
+ def __init__(self, parent):
25
+ LineEdit.__init__(self, parent)
26
+ self.editComplete.connect(self._update_name)
27
+ self.nameChanged.connect(self._handle_name_changed)
28
+ self.defaultNameChanged.connect(self._handle_name_changed)
29
+
30
+ defaultNameChanged = pyqtSignal(str)
31
+ nameChanged = pyqtSignal(str)
32
+
33
+ defaultName = AutoProperty(str)
34
+ name = AutoProperty(str)
35
+
36
+ def focusInEvent(self, event):
37
+ self._handle_interaction()
38
+ LineEdit.focusInEvent(self, event)
39
+
40
+ def _update_name(self, value):
41
+ self.name = value
42
+
43
+ def _handle_name_changed(self):
44
+ self.setText(self.name)
45
+ if not self.name:
46
+ self.setPlaceholderText(self.defaultName)
47
+
48
+ def _handle_interaction(self):
49
+ if not self.name:
50
+ self.name = self.defaultName
@@ -0,0 +1,117 @@
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
18
+
19
+ from PyQt5.QtCore import QStringListModel, Qt, QDateTime
20
+ from PyQt5.QtWidgets import QStyledItemDelegate, QTableView, QWidget, QHBoxLayout, QPushButton
21
+
22
+ from pyqttoolkit.models.roles import DataRole, EditorAuxDataRole
23
+ from pyqttoolkit.views import BindableComboBox, DateTimeEdit, BulkValueSelectorWidget, Popup
24
+
25
+ class ComboBoxItemDelegate(QStyledItemDelegate):
26
+ def __init__(self, parent):
27
+ super().__init__(parent)
28
+
29
+ def setComboBoxModel(self, model):
30
+ self._combo_box_model = model
31
+
32
+ def createEditor(self, parent, option, index):
33
+ combo_box = BindableComboBox(parent)
34
+ combo_box.setModel(self._combo_box_model)
35
+ combo_box.move(parent.pos())
36
+ value = self.parent().model().data(index, DataRole)
37
+ if isinstance(self.parent(), QTableView):
38
+ combo_box.setFixedWidth(self.parent().columnWidth(index.column()) * self.parent().columnSpan(index.row(), index.column()))
39
+ combo_box.setFixedHeight(self.parent().rowHeight(index.row()) * self.parent().rowSpan(index.row(), index.column()))
40
+ else:
41
+ combo_box.setFixedWidth(self.parent().columnWidth(index.column()))
42
+ combo_box.setFixedHeight(self.parent().rowHeight(index))
43
+ if isinstance(value, Enum):
44
+ value = value.name
45
+ combo_box.value = value
46
+ combo_box.currentIndexChanged.connect(self.closeEditor(combo_box))
47
+ return combo_box
48
+
49
+ def setEditorData(self, editor, index):
50
+ editor.showPopup()
51
+
52
+ def closeEditor(self, control):
53
+ def _handler():
54
+ self.parent().commitData(control)
55
+ self.parent().closeEditor(control, QStyledItemDelegate.NoHint)
56
+ return _handler
57
+
58
+ class DateTimeItemDelegate(QStyledItemDelegate):
59
+ def __init__(self, parent):
60
+ super().__init__(parent)
61
+ self._popup = None
62
+
63
+ def createEditor(self, parent, option, index):
64
+ date_range, default = self.parent().model().data(index, EditorAuxDataRole)
65
+ editor = DateTimeEdit(parent, default)
66
+ editor.setDateTimeRange(*date_range)
67
+ value = self.parent().model().data(index, DataRole)
68
+ editor.value = QDateTime(value) if value is not None else None
69
+ if default is not None:
70
+ reset_button_text = self.tr('Set to Start') if default == DateTimeEdit.Limit.min else self.tr('Set to End')
71
+ start_end_buttons = QWidget(parent)
72
+ start_end_buttons_layout = QHBoxLayout(start_end_buttons)
73
+ start_end_buttons_layout.setContentsMargins(0, 0, 0, 0)
74
+ button = QPushButton(reset_button_text, start_end_buttons)
75
+ button.clicked.connect(editor.reset)
76
+ start_end_buttons_layout.addWidget(button)
77
+ self._popup = Popup(editor, start_end_buttons)
78
+
79
+ return editor
80
+
81
+ def setEditorData(self, editor, index):
82
+ if self._popup is not None:
83
+ cell_rect = editor.rect()
84
+ self._popup.popupAtPosition(editor, cell_rect.bottomLeft())
85
+ return super().setEditorData(editor, index)
86
+
87
+ def setModelData(self, editor, model, index):
88
+ if self._popup is not None:
89
+ self._popup.close()
90
+ self._popup = None
91
+ model.setData(index, editor.value, Qt.EditRole)
92
+
93
+
94
+ class BulkValueSelectorItemDelegate(QStyledItemDelegate):
95
+ def __init__(self, parent):
96
+ super().__init__(parent)
97
+
98
+ def createEditor(self, parent, option, index):
99
+ editor = BulkValueSelectorWidget(parent)
100
+ editor.setFixedHeight(int(self.parent().height() * 0.8))
101
+ editor.setFixedWidth(200)
102
+ editor.values = QStringListModel(self.parent().model().data(index, EditorAuxDataRole), self)
103
+ editor.selectedValues = self.parent().model().data(index, DataRole)
104
+ popup = Popup(parent, editor)
105
+ editor.dataCommitted.connect(self.closePopup(popup))
106
+ return popup
107
+
108
+ def setEditorData(self, editor, index):
109
+ editor.popupAtPosition(self.parent(), self.parent().visualRect(index))
110
+
111
+ def setModelData(self, editor, model, index):
112
+ model.setData(index, sorted(editor.contents.selectedValues))
113
+
114
+ def closePopup(self, popup):
115
+ def _handler(selected_values):
116
+ self.parent().closeEditor(popup, QStyledItemDelegate.NoHint)
117
+ return _handler