--- a/eric6/UI/NotificationWidget.py Mon Jan 04 15:51:18 2021 +0100 +++ b/eric6/UI/NotificationWidget.py Mon Jan 04 15:59:22 2021 +0100 @@ -8,34 +8,68 @@ """ from PyQt5.QtCore import Qt, QTimer, QPoint -from PyQt5.QtGui import QPixmap -from PyQt5.QtWidgets import QWidget +from PyQt5.QtWidgets import QFrame, QWidget, QVBoxLayout -from .Ui_NotificationWidget import Ui_NotificationWidget +from .Ui_NotificationFrame import Ui_NotificationFrame import Globals +import Preferences -class NotificationWidget(QWidget, Ui_NotificationWidget): +class NotificationFrame(QFrame, Ui_NotificationFrame): """ Class implementing a Notification widget. """ + def __init__(self, icon, heading, text, parent=None): + """ + Constructor + + @param icon icon to be used + @type QPixmap + @param heading heading to be used + @type str + @param text text to be used + @type str + @param parent reference to the parent widget + @type QWidget + """ + super(NotificationFrame, self).__init__(parent) + self.setupUi(self) + + self.layout().setAlignment( + self.verticalLayout, Qt.AlignLeft | Qt.AlignVCenter) + + self.icon.setPixmap(icon) + self.heading.setText(heading) + self.text.setText(text) + + self.show() + self.adjustSize() + + +class NotificationWidget(QWidget): + """ + Class implementing a Notification list widget. + """ def __init__(self, parent=None, setPosition=False): """ Constructor - @param parent reference to the parent widget (QWidget) + @param parent reference to the parent widget + @type QWidget @param setPosition flag indicating to set the display - position interactively (boolean) + position interactively + @type bool """ super(NotificationWidget, self).__init__(parent) - self.setupUi(self) + + self.__layout = QVBoxLayout(self) + self.__layout.setContentsMargins(0, 0, 0, 0) + self.setLayout(self.__layout) self.__timeout = 5000 - self.__icon = QPixmap() - self.__heading = "" - self.__text = "" self.__dragPosition = QPoint() + self.__timers = {} self.__settingPosition = setPosition @@ -49,67 +83,92 @@ flags |= Qt.ToolTip self.setWindowFlags(flags) - self.frame.layout().setAlignment( - self.verticalLayout, Qt.AlignLeft | Qt.AlignVCenter) - - self.__timer = QTimer(self) - self.__timer.setSingleShot(True) - self.__timer.timeout.connect(self.close) - if self.__settingPosition: self.setCursor(Qt.OpenHandCursor) - def setPixmap(self, icon): - """ - Public method to set the icon for the notification. - - @param icon icon to be used (QPixmap) - """ - self.__icon = QPixmap(icon) - - def setHeading(self, heading): + def showNotification(self, icon, heading, text, timeout=0): """ - Public method to set the heading for the notification. + Public method to show a notification. - @param heading heading to be used (string) + @param icon icon to be used + @type QPixmap + @param heading heading to be used + @type str + @param text text to be used + @type str + @param timeout timeout in seconds after which the notification is + to be removed (0 = do not remove until it is clicked on) """ - self.__heading = heading - - def setText(self, text): - """ - Public method to set the text for the notification. + notificationFrame = NotificationFrame(icon, heading, text, self) + self.__layout.addWidget(notificationFrame) + + self.show() - @param text text to be used (string) - """ - self.__text = text - - def setTimeout(self, timeout): - """ - Public method to set the timeout for the notification. + self.__adjustSizeAndPosition() - @param timeout timeout to be used in seconds (0 = indefinitely) - @type int - """ - self.__timeout = timeout * 1000 + if timeout: + timer = QTimer() + self.__timers[repr(notificationFrame)] = timer + timer.setSingleShot(True) + timer.timeout.connect( + lambda: self.__removeNotification(notificationFrame) + ) + timer.setInterval(timeout * 1000) + timer.start() - def show(self): - """ - Public method to show the notification. + def __adjustSizeAndPosition(self): """ - self.icon.setPixmap(self.__icon) - self.heading.setText(self.__heading) - self.text.setText(self.__text) + Private slot to adjust the notification list widget size and position. + """ + self.adjustSize() if not self.__settingPosition: - self.__timer.stop() - if self.__timeout > 0: - self.__timer.setInterval(self.__timeout) - self.__timer.start() + pos = Preferences.getUI("NotificationPosition") + try: + screen = self.screen() + except AttributeError: + # < Qt 5.15 + from PyQt5.QtGui import QGuiApplication + screen = QGuiApplication.screenAt(pos) + screenGeom = screen.geometry() + + newX = pos.x() + newY = pos.y() + if newX < screenGeom.x(): + newX = screenGeom.x() + if newY < screenGeom.y(): + newY = screenGeom.y() + if newX + self.width() > screenGeom.width(): + newX = screenGeom.width() - self.width() + if newY + self.height() > screenGeom.height(): + newY = screenGeom.height() - self.height() + + self.move(newX, newY) + + def __removeNotification(self, notification): + """ + Private method to remove a notification from the list. - super(NotificationWidget, self).show() + @param notification reference to the notification to be removed + @type NotificationFrame + """ + notification.hide() - sh = self.sizeHint() - self.resize(max(self.width(), sh.width()), sh.height()) + # delete timer of an auto close notification + key = repr(notification) + if key in self.__timers: + self.__timers[key].stop() + del self.__timers[key] + + # delete the notification + index = self.__layout.indexOf(notification) + self.__layout.takeAt(index) + notification.deleteLater() + + if self.__layout.count(): + self.__adjustSizeAndPosition() + else: + self.close() def mousePressEvent(self, evt): """ @@ -118,7 +177,9 @@ @param evt reference to the mouse event (QMouseEvent) """ if not self.__settingPosition: - self.close() + clickedLabel = self.childAt(evt.pos()) + clickedNotification = clickedLabel.parent() + self.__removeNotification(clickedNotification) return if evt.button() == Qt.LeftButton: