eric6/UI/NotificationWidget.py

changeset 7952
1849f61cf2b6
parent 7923
91e843545d9a
child 7956
7db67b70e6a8
diff -r fa058239133f -r 1849f61cf2b6 eric6/UI/NotificationWidget.py
--- 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:

eric ide

mercurial