6 """ |
6 """ |
7 Module implementing a Notification widget. |
7 Module implementing a Notification widget. |
8 """ |
8 """ |
9 |
9 |
10 from PyQt5.QtCore import Qt, QTimer, QPoint |
10 from PyQt5.QtCore import Qt, QTimer, QPoint |
11 from PyQt5.QtGui import QPixmap |
11 from PyQt5.QtWidgets import QFrame, QWidget, QVBoxLayout |
12 from PyQt5.QtWidgets import QWidget |
12 |
13 |
13 from .Ui_NotificationFrame import Ui_NotificationFrame |
14 from .Ui_NotificationWidget import Ui_NotificationWidget |
|
15 |
14 |
16 import Globals |
15 import Globals |
17 |
16 import Preferences |
18 |
17 |
19 class NotificationWidget(QWidget, Ui_NotificationWidget): |
18 |
|
19 class NotificationFrame(QFrame, Ui_NotificationFrame): |
20 """ |
20 """ |
21 Class implementing a Notification widget. |
21 Class implementing a Notification widget. |
22 """ |
22 """ |
|
23 def __init__(self, icon, heading, text, parent=None): |
|
24 """ |
|
25 Constructor |
|
26 |
|
27 @param icon icon to be used |
|
28 @type QPixmap |
|
29 @param heading heading to be used |
|
30 @type str |
|
31 @param text text to be used |
|
32 @type str |
|
33 @param parent reference to the parent widget |
|
34 @type QWidget |
|
35 """ |
|
36 super(NotificationFrame, self).__init__(parent) |
|
37 self.setupUi(self) |
|
38 |
|
39 self.layout().setAlignment( |
|
40 self.verticalLayout, Qt.AlignLeft | Qt.AlignVCenter) |
|
41 |
|
42 self.icon.setPixmap(icon) |
|
43 self.heading.setText(heading) |
|
44 self.text.setText(text) |
|
45 |
|
46 self.show() |
|
47 self.adjustSize() |
|
48 |
|
49 |
|
50 class NotificationWidget(QWidget): |
|
51 """ |
|
52 Class implementing a Notification list widget. |
|
53 """ |
23 def __init__(self, parent=None, setPosition=False): |
54 def __init__(self, parent=None, setPosition=False): |
24 """ |
55 """ |
25 Constructor |
56 Constructor |
26 |
57 |
27 @param parent reference to the parent widget (QWidget) |
58 @param parent reference to the parent widget |
|
59 @type QWidget |
28 @param setPosition flag indicating to set the display |
60 @param setPosition flag indicating to set the display |
29 position interactively (boolean) |
61 position interactively |
|
62 @type bool |
30 """ |
63 """ |
31 super(NotificationWidget, self).__init__(parent) |
64 super(NotificationWidget, self).__init__(parent) |
32 self.setupUi(self) |
65 |
|
66 self.__layout = QVBoxLayout(self) |
|
67 self.__layout.setContentsMargins(0, 0, 0, 0) |
|
68 self.setLayout(self.__layout) |
33 |
69 |
34 self.__timeout = 5000 |
70 self.__timeout = 5000 |
35 self.__icon = QPixmap() |
|
36 self.__heading = "" |
|
37 self.__text = "" |
|
38 self.__dragPosition = QPoint() |
71 self.__dragPosition = QPoint() |
|
72 self.__timers = {} |
39 |
73 |
40 self.__settingPosition = setPosition |
74 self.__settingPosition = setPosition |
41 |
75 |
42 flags = ( |
76 flags = ( |
43 Qt.Tool | |
77 Qt.Tool | |
47 ) |
81 ) |
48 if Globals.isWindowsPlatform(): |
82 if Globals.isWindowsPlatform(): |
49 flags |= Qt.ToolTip |
83 flags |= Qt.ToolTip |
50 self.setWindowFlags(flags) |
84 self.setWindowFlags(flags) |
51 |
85 |
52 self.frame.layout().setAlignment( |
|
53 self.verticalLayout, Qt.AlignLeft | Qt.AlignVCenter) |
|
54 |
|
55 self.__timer = QTimer(self) |
|
56 self.__timer.setSingleShot(True) |
|
57 self.__timer.timeout.connect(self.close) |
|
58 |
|
59 if self.__settingPosition: |
86 if self.__settingPosition: |
60 self.setCursor(Qt.OpenHandCursor) |
87 self.setCursor(Qt.OpenHandCursor) |
61 |
88 |
62 def setPixmap(self, icon): |
89 def showNotification(self, icon, heading, text, timeout=0): |
63 """ |
90 """ |
64 Public method to set the icon for the notification. |
91 Public method to show a notification. |
65 |
92 |
66 @param icon icon to be used (QPixmap) |
93 @param icon icon to be used |
67 """ |
94 @type QPixmap |
68 self.__icon = QPixmap(icon) |
95 @param heading heading to be used |
69 |
96 @type str |
70 def setHeading(self, heading): |
97 @param text text to be used |
71 """ |
98 @type str |
72 Public method to set the heading for the notification. |
99 @param timeout timeout in seconds after which the notification is |
73 |
100 to be removed (0 = do not remove until it is clicked on) |
74 @param heading heading to be used (string) |
101 """ |
75 """ |
102 notificationFrame = NotificationFrame(icon, heading, text, self) |
76 self.__heading = heading |
103 self.__layout.addWidget(notificationFrame) |
77 |
104 |
78 def setText(self, text): |
105 self.show() |
79 """ |
106 |
80 Public method to set the text for the notification. |
107 self.__adjustSizeAndPosition() |
81 |
108 |
82 @param text text to be used (string) |
109 if timeout: |
83 """ |
110 timer = QTimer() |
84 self.__text = text |
111 self.__timers[repr(notificationFrame)] = timer |
85 |
112 timer.setSingleShot(True) |
86 def setTimeout(self, timeout): |
113 timer.timeout.connect( |
87 """ |
114 lambda: self.__removeNotification(notificationFrame) |
88 Public method to set the timeout for the notification. |
115 ) |
89 |
116 timer.setInterval(timeout * 1000) |
90 @param timeout timeout to be used in seconds (0 = indefinitely) |
117 timer.start() |
91 @type int |
118 |
92 """ |
119 def __adjustSizeAndPosition(self): |
93 self.__timeout = timeout * 1000 |
120 """ |
94 |
121 Private slot to adjust the notification list widget size and position. |
95 def show(self): |
122 """ |
96 """ |
123 self.adjustSize() |
97 Public method to show the notification. |
|
98 """ |
|
99 self.icon.setPixmap(self.__icon) |
|
100 self.heading.setText(self.__heading) |
|
101 self.text.setText(self.__text) |
|
102 |
124 |
103 if not self.__settingPosition: |
125 if not self.__settingPosition: |
104 self.__timer.stop() |
126 pos = Preferences.getUI("NotificationPosition") |
105 if self.__timeout > 0: |
127 try: |
106 self.__timer.setInterval(self.__timeout) |
128 screen = self.screen() |
107 self.__timer.start() |
129 except AttributeError: |
108 |
130 # < Qt 5.15 |
109 super(NotificationWidget, self).show() |
131 from PyQt5.QtGui import QGuiApplication |
110 |
132 screen = QGuiApplication.screenAt(pos) |
111 sh = self.sizeHint() |
133 screenGeom = screen.geometry() |
112 self.resize(max(self.width(), sh.width()), sh.height()) |
134 |
|
135 newX = pos.x() |
|
136 newY = pos.y() |
|
137 if newX < screenGeom.x(): |
|
138 newX = screenGeom.x() |
|
139 if newY < screenGeom.y(): |
|
140 newY = screenGeom.y() |
|
141 if newX + self.width() > screenGeom.width(): |
|
142 newX = screenGeom.width() - self.width() |
|
143 if newY + self.height() > screenGeom.height(): |
|
144 newY = screenGeom.height() - self.height() |
|
145 |
|
146 self.move(newX, newY) |
|
147 |
|
148 def __removeNotification(self, notification): |
|
149 """ |
|
150 Private method to remove a notification from the list. |
|
151 |
|
152 @param notification reference to the notification to be removed |
|
153 @type NotificationFrame |
|
154 """ |
|
155 notification.hide() |
|
156 |
|
157 # delete timer of an auto close notification |
|
158 key = repr(notification) |
|
159 if key in self.__timers: |
|
160 self.__timers[key].stop() |
|
161 del self.__timers[key] |
|
162 |
|
163 # delete the notification |
|
164 index = self.__layout.indexOf(notification) |
|
165 self.__layout.takeAt(index) |
|
166 notification.deleteLater() |
|
167 |
|
168 if self.__layout.count(): |
|
169 self.__adjustSizeAndPosition() |
|
170 else: |
|
171 self.close() |
113 |
172 |
114 def mousePressEvent(self, evt): |
173 def mousePressEvent(self, evt): |
115 """ |
174 """ |
116 Protected method to handle presses of a mouse button. |
175 Protected method to handle presses of a mouse button. |
117 |
176 |
118 @param evt reference to the mouse event (QMouseEvent) |
177 @param evt reference to the mouse event (QMouseEvent) |
119 """ |
178 """ |
120 if not self.__settingPosition: |
179 if not self.__settingPosition: |
121 self.close() |
180 clickedLabel = self.childAt(evt.pos()) |
|
181 clickedNotification = clickedLabel.parent() |
|
182 self.__removeNotification(clickedNotification) |
122 return |
183 return |
123 |
184 |
124 if evt.button() == Qt.LeftButton: |
185 if evt.button() == Qt.LeftButton: |
125 self.__dragPosition = ( |
186 self.__dragPosition = ( |
126 evt.globalPos() - self.frameGeometry().topLeft() |
187 evt.globalPos() - self.frameGeometry().topLeft() |