Files
Traffic-Intersection-Monito…/qt_app_pyside1/ui/widgets/notification_center.py
2025-08-26 13:24:53 -07:00

281 lines
9.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Notification Center Widget - Modern notification panel with filtering and management
"""
from PySide6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel,
QPushButton, QScrollArea, QFrame, QComboBox,
QLineEdit, QCheckBox, QSizePolicy)
from PySide6.QtCore import Qt, Signal, QTimer, QDateTime
from PySide6.QtGui import QFont, QIcon
class NotificationItem(QFrame):
"""Individual notification item with modern styling"""
dismissed = Signal(object) # Emitted when notification is dismissed
def __init__(self, message, level="info", timestamp=None, parent=None):
super().__init__(parent)
self.message = message
self.level = level
self.timestamp = timestamp or QDateTime.currentDateTime()
self.setObjectName(f"notificationItem_{level}")
self.setFrameStyle(QFrame.Box)
self.setMaximumHeight(80)
self._setup_ui()
self._apply_style()
# Auto-dismiss timer for info notifications
if level == "info":
QTimer.singleShot(10000, self._auto_dismiss) # 10 seconds
def _setup_ui(self):
"""Setup the notification item UI"""
layout = QHBoxLayout(self)
layout.setContentsMargins(10, 8, 10, 8)
# Level icon
icon_label = QLabel()
icon_label.setFixedSize(24, 24)
icon_label.setAlignment(Qt.AlignCenter)
icons = {
'info': '💡',
'warning': '⚠️',
'error': '',
'success': ''
}
icon_label.setText(icons.get(self.level, '📋'))
icon_label.setStyleSheet("font-size: 16px;")
layout.addWidget(icon_label)
# Content area
content_layout = QVBoxLayout()
# Message
message_label = QLabel(self.message)
message_label.setWordWrap(True)
message_label.setFont(QFont("Segoe UI", 9))
content_layout.addWidget(message_label)
# Timestamp
time_label = QLabel(self.timestamp.toString("hh:mm:ss"))
time_label.setFont(QFont("Segoe UI", 8))
time_label.setStyleSheet("color: gray;")
content_layout.addWidget(time_label)
layout.addLayout(content_layout, 1)
# Dismiss button
dismiss_btn = QPushButton("×")
dismiss_btn.setFixedSize(20, 20)
dismiss_btn.setFont(QFont("Arial", 10, QFont.Bold))
dismiss_btn.clicked.connect(self._dismiss)
layout.addWidget(dismiss_btn)
def _apply_style(self):
"""Apply level-specific styling"""
styles = {
'info': "border-left: 3px solid #3498db; background-color: rgba(52, 152, 219, 0.1);",
'warning': "border-left: 3px solid #f39c12; background-color: rgba(243, 156, 18, 0.1);",
'error': "border-left: 3px solid #e74c3c; background-color: rgba(231, 76, 60, 0.1);",
'success': "border-left: 3px solid #27ae60; background-color: rgba(39, 174, 96, 0.1);"
}
self.setStyleSheet(styles.get(self.level, styles['info']))
def _dismiss(self):
"""Dismiss this notification"""
self.dismissed.emit(self)
def _auto_dismiss(self):
"""Auto-dismiss for info notifications"""
if self.level == "info":
self._dismiss()
class NotificationCenter(QWidget):
"""
Modern notification center with filtering and management capabilities
"""
def __init__(self, parent=None):
super().__init__(parent)
self.setFixedWidth(350)
self.notifications = []
self.max_notifications = 50
self._setup_ui()
print("✅ Notification Center initialized")
def _setup_ui(self):
"""Setup the notification center UI"""
layout = QVBoxLayout(self)
layout.setContentsMargins(10, 10, 10, 10)
layout.setSpacing(5)
# Header
header = self._create_header()
layout.addWidget(header)
# Filter controls
filters = self._create_filters()
layout.addWidget(filters)
# Notification list
self.scroll_area = QScrollArea()
self.scroll_area.setWidgetResizable(True)
self.scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarNever)
self.notifications_widget = QWidget()
self.notifications_layout = QVBoxLayout(self.notifications_widget)
self.notifications_layout.setAlignment(Qt.AlignTop)
self.scroll_area.setWidget(self.notifications_widget)
layout.addWidget(self.scroll_area)
# Footer with actions
footer = self._create_footer()
layout.addWidget(footer)
def _create_header(self):
"""Create the header with title and controls"""
header = QFrame()
header.setFixedHeight(40)
layout = QHBoxLayout(header)
# Title
title = QLabel("Notifications")
title.setFont(QFont("Segoe UI", 11, QFont.Bold))
layout.addWidget(title)
layout.addStretch()
# Notification count
self.count_label = QLabel("0")
self.count_label.setFont(QFont("Segoe UI", 9))
self.count_label.setStyleSheet("color: gray;")
layout.addWidget(self.count_label)
return header
def _create_filters(self):
"""Create filter controls"""
filters = QFrame()
filters.setFixedHeight(35)
layout = QHBoxLayout(filters)
layout.setContentsMargins(0, 0, 0, 0)
# Level filter
self.level_filter = QComboBox()
self.level_filter.addItems(["All", "Info", "Warning", "Error", "Success"])
self.level_filter.currentTextChanged.connect(self._apply_filters)
layout.addWidget(self.level_filter)
# Search filter
self.search_filter = QLineEdit()
self.search_filter.setPlaceholderText("Search notifications...")
self.search_filter.textChanged.connect(self._apply_filters)
layout.addWidget(self.search_filter)
return filters
def _create_footer(self):
"""Create footer with action buttons"""
footer = QFrame()
footer.setFixedHeight(35)
layout = QHBoxLayout(footer)
# Clear all button
clear_btn = QPushButton("Clear All")
clear_btn.clicked.connect(self.clear_all)
layout.addWidget(clear_btn)
layout.addStretch()
# Export button
export_btn = QPushButton("Export")
export_btn.clicked.connect(self._export_notifications)
layout.addWidget(export_btn)
return footer
def add_notification(self, message, level="info"):
"""Add a new notification"""
# Remove oldest notification if at limit
if len(self.notifications) >= self.max_notifications:
oldest = self.notifications[0]
self._remove_notification(oldest)
# Create new notification
notification = NotificationItem(message, level)
notification.dismissed.connect(self._remove_notification)
# Add to list and layout
self.notifications.append(notification)
self.notifications_layout.insertWidget(0, notification) # Add to top
# Update count
self._update_count()
# Scroll to top to show new notification
self.scroll_area.verticalScrollBar().setValue(0)
print(f"📝 Notification added: {level.upper()} - {message[:50]}...")
def _remove_notification(self, notification):
"""Remove a notification"""
if notification in self.notifications:
self.notifications.remove(notification)
notification.setParent(None)
self._update_count()
def _apply_filters(self):
"""Apply current filters to notifications"""
level_filter = self.level_filter.currentText().lower()
search_text = self.search_filter.text().lower()
for notification in self.notifications:
# Check level filter
level_match = (level_filter == "all" or
notification.level == level_filter)
# Check search filter
search_match = (not search_text or
search_text in notification.message.lower())
# Show/hide notification
notification.setVisible(level_match and search_match)
def _update_count(self):
"""Update the notification count"""
visible_count = sum(1 for n in self.notifications if n.isVisible())
total_count = len(self.notifications)
self.count_label.setText(f"{visible_count}/{total_count}")
def clear_all(self):
"""Clear all notifications"""
for notification in self.notifications[:]: # Copy list to avoid modification during iteration
self._remove_notification(notification)
def _export_notifications(self):
"""Export notifications to file"""
# Implementation for exporting notifications
print("📤 Exporting notifications...")
def get_notification_summary(self):
"""Get summary of current notifications"""
summary = {
'total': len(self.notifications),
'by_level': {}
}
for notification in self.notifications:
level = notification.level
summary['by_level'][level] = summary['by_level'].get(level, 0) + 1
return summary