""" Tab zur Verwaltung der erstellten Social-Media-Accounts. """ import logging from PyQt5.QtWidgets import ( QWidget, QVBoxLayout, QHBoxLayout, QTableWidget, QTableWidgetItem, QPushButton, QHeaderView, QMessageBox ) from PyQt5.QtCore import pyqtSignal, Qt, QEvent from PyQt5.QtGui import QWheelEvent, QColor logger = logging.getLogger("accounts_tab") class HorizontalScrollTableWidget(QTableWidget): """Custom QTableWidget that supports horizontal scrolling with mouse wheel.""" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Install event filter to handle wheel events self.viewport().installEventFilter(self) def eventFilter(self, source, event): """Event filter to handle horizontal scrolling with mouse wheel.""" if source == self.viewport() and event.type() == QEvent.Wheel: # Cast to QWheelEvent wheel_event = event # Check if horizontal scrollbar is visible and vertical is not needed h_bar = self.horizontalScrollBar() v_bar = self.verticalScrollBar() # If Shift is pressed, use default behavior (horizontal scroll) if event.modifiers() & Qt.ShiftModifier: return super().eventFilter(source, event) # Smart scrolling logic if h_bar.isVisible(): # Check if vertical scrolling is at limits or not needed vertical_at_limit = ( not v_bar.isVisible() or (v_bar.value() == v_bar.minimum() and wheel_event.angleDelta().y() > 0) or (v_bar.value() == v_bar.maximum() and wheel_event.angleDelta().y() < 0) ) # If vertical is not needed or at limit, scroll horizontally if not v_bar.isVisible() or vertical_at_limit: # Get the delta (negative for scroll down, positive for scroll up) delta = wheel_event.angleDelta().y() # Calculate new position (invert delta for natural scrolling) step = h_bar.singleStep() * 3 # Make scrolling faster new_value = h_bar.value() - (delta // 120) * step # Apply the new position h_bar.setValue(new_value) # Mark event as handled return True return super().eventFilter(source, event) class AccountsTab(QWidget): """Widget für den Konten-Tab.""" # Signale export_requested = pyqtSignal() delete_requested = pyqtSignal(int) # account_id login_requested = pyqtSignal(str, str) # account_id, platform def __init__(self, platform_name=None, db_manager=None, language_manager=None): super().__init__() self.platform_name = platform_name self.db_manager = db_manager self.language_manager = language_manager self.init_ui() if self.language_manager: self.language_manager.language_changed.connect(self.update_texts) self.update_texts() # Konten laden, falls db_manager vorhanden if self.db_manager: self.load_accounts() def init_ui(self): """Initialisiert die Benutzeroberfläche.""" layout = QVBoxLayout(self) # Konten-Tabelle mit horizontalem Mausrad-Support self.accounts_table = HorizontalScrollTableWidget() self.accounts_table.setColumnCount(9) self.accounts_table.setHorizontalHeaderLabels([ "ID", "Benutzername", "Passwort", "E-Mail", "Handynummer", "Name", "Plattform", "Erstellt am", "Session" ]) # Enable horizontal scrolling and set minimum column widths self.accounts_table.horizontalHeader().setSectionResizeMode(QHeaderView.Interactive) self.accounts_table.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.accounts_table.setHorizontalScrollMode(QTableWidget.ScrollPerPixel) # Set minimum column widths to prevent text overlap self.accounts_table.setColumnWidth(0, 50) # ID self.accounts_table.setColumnWidth(1, 150) # Benutzername self.accounts_table.setColumnWidth(2, 150) # Passwort self.accounts_table.setColumnWidth(3, 250) # E-Mail self.accounts_table.setColumnWidth(4, 150) # Handynummer self.accounts_table.setColumnWidth(5, 150) # Name self.accounts_table.setColumnWidth(6, 130) # Plattform self.accounts_table.setColumnWidth(7, 150) # Erstellt am # ID-Spalte verstecken self.accounts_table.setColumnHidden(0, True) # Explizite Zeilenhöhe setzen, um Abschneiden zu verhindern self.accounts_table.verticalHeader().setDefaultSectionSize(40) self.accounts_table.verticalHeader().setMinimumSectionSize(35) layout.addWidget(self.accounts_table) # Button-Leiste button_layout = QHBoxLayout() self.login_button = QPushButton("🔑 Login") self.login_button.clicked.connect(self.on_login_clicked) self.login_button.setToolTip("Mit gespeicherter Session einloggen") self.export_button = QPushButton("Exportieren") self.export_button.clicked.connect(self.on_export_clicked) self.delete_button = QPushButton("Löschen") self.delete_button.clicked.connect(self.on_delete_clicked) button_layout.addWidget(self.login_button) button_layout.addWidget(self.export_button) button_layout.addWidget(self.delete_button) layout.addLayout(button_layout) def load_accounts(self): """Lädt Konten aus der Datenbank und zeigt sie in der Tabelle an.""" try: if (self.platform_name and str(self.platform_name).lower() not in ["all", ""] and hasattr(self.db_manager, "get_accounts_by_platform")): accounts = self.db_manager.get_accounts_by_platform(self.platform_name.lower()) else: accounts = self.db_manager.get_all_accounts() if self.platform_name and str(self.platform_name).lower() not in ["all", ""]: accounts = [ acc for acc in accounts if acc.get("platform", "").lower() == str(self.platform_name).lower() ] self.display_accounts(accounts) except Exception as e: logger.error(f"Fehler beim Laden der Konten: {e}") QMessageBox.critical(self, "Fehler", f"Fehler beim Laden der Konten:\n{str(e)}") def display_accounts(self, accounts): """Zeigt die Konten in der Tabelle an.""" self.accounts_table.setRowCount(len(accounts)) for row, account in enumerate(accounts): self.accounts_table.setItem(row, 0, QTableWidgetItem(str(account.get("id", "")))) self.accounts_table.setItem(row, 1, QTableWidgetItem(account.get("username", ""))) self.accounts_table.setItem(row, 2, QTableWidgetItem(account.get("password", ""))) self.accounts_table.setItem(row, 3, QTableWidgetItem(account.get("email", ""))) self.accounts_table.setItem(row, 4, QTableWidgetItem(account.get("phone", ""))) self.accounts_table.setItem(row, 5, QTableWidgetItem(account.get("full_name", ""))) self.accounts_table.setItem(row, 6, QTableWidgetItem(account.get("platform", ""))) self.accounts_table.setItem(row, 7, QTableWidgetItem(account.get("created_at", ""))) # Account Status hinzufügen mit visueller Darstellung status = account.get("status", "active") # Standard: active (grün) status_text = self._format_status_text(status) status_item = QTableWidgetItem(status_text) status_item.setToolTip(self._get_status_tooltip(status)) # Status-basierte Hintergrundfarben für Tabellenzellen (nur Grün/Rot) if status == "active": status_item.setBackground(QColor("#F0FDF4")) # Helles Grün elif status == "inactive": status_item.setBackground(QColor("#FEF2F2")) # Helles Rot else: # Fallback auf active (grün) status_item.setBackground(QColor("#F0FDF4")) self.accounts_table.setItem(row, 8, status_item) def on_login_clicked(self): """Wird aufgerufen, wenn der Login-Button geklickt wird.""" selected_rows = self.accounts_table.selectionModel().selectedRows() if not selected_rows: title = "Kein Konto ausgewählt" text = "Bitte wählen Sie ein Konto zum Einloggen aus." if self.language_manager: title = self.language_manager.get_text( "accounts_tab.no_selection_title", title ) text = self.language_manager.get_text( "accounts_tab.no_login_selection_text", text ) QMessageBox.warning(self, title, text) return row = selected_rows[0].row() account_id = self.accounts_table.item(row, 0).text() platform = self.accounts_table.item(row, 6).text() self.login_requested.emit(account_id, platform) def on_export_clicked(self): """Wird aufgerufen, wenn der Exportieren-Button geklickt wird.""" self.export_requested.emit() def update_session_status(self, account_id: str, status: dict): """ Session-Status-Update deaktiviert (Session-Funktionalität entfernt). """ # Session-Funktionalität wurde entfernt - diese Methode macht nichts mehr pass def on_delete_clicked(self): """Wird aufgerufen, wenn der Löschen-Button geklickt wird.""" selected_rows = self.accounts_table.selectionModel().selectedRows() if not selected_rows: title = "Kein Konto ausgewählt" text = "Bitte wählen Sie ein Konto zum Löschen aus." if self.language_manager: title = self.language_manager.get_text( "accounts_tab.no_selection_title", title ) text = self.language_manager.get_text( "accounts_tab.no_selection_text", text ) QMessageBox.warning(self, title, text) return account_id = int(self.accounts_table.item(selected_rows[0].row(), 0).text()) username = self.accounts_table.item(selected_rows[0].row(), 1).text() q_title = "Konto löschen" q_text = f"Möchten Sie das Konto '{username}' wirklich löschen?" if self.language_manager: q_title = self.language_manager.get_text("accounts_tab.delete_title", q_title) q_text = self.language_manager.get_text( "accounts_tab.delete_text", q_text ).format(username=username) reply = QMessageBox.question( self, q_title, q_text, QMessageBox.Yes | QMessageBox.No, QMessageBox.No, ) if reply == QMessageBox.Yes: self.delete_requested.emit(account_id) # Direkt aktualisieren, falls db_manager vorhanden if self.db_manager: success = self.db_manager.delete_account(account_id) if success: self.load_accounts() suc_title = "Erfolg" suc_text = f"Konto '{username}' wurde gelöscht." if self.language_manager: suc_title = self.language_manager.get_text( "accounts_tab.delete_success_title", suc_title ) suc_text = self.language_manager.get_text( "accounts_tab.delete_success_text", suc_text ).format(username=username) QMessageBox.information(self, suc_title, suc_text) else: err_title = "Fehler" err_text = f"Konto '{username}' konnte nicht gelöscht werden." if self.language_manager: err_title = self.language_manager.get_text( "accounts_tab.delete_error_title", err_title ) err_text = self.language_manager.get_text( "accounts_tab.delete_error_text", err_text ).format(username=username) QMessageBox.critical(self, err_title, err_text) def update_texts(self): """Aktualisiert UI-Texte gemäß aktueller Sprache.""" if not self.language_manager: return lm = self.language_manager self.login_button.setText(lm.get_text("buttons.login", "🔑 Login")) self.export_button.setText(lm.get_text("buttons.export", "Exportieren")) self.delete_button.setText(lm.get_text("buttons.delete", "Löschen")) headers = lm.get_text( "accounts_tab.headers", [ "ID", "Benutzername", "Passwort", "E-Mail", "Handynummer", "Name", "Plattform", "Erstellt am", ], ) self.accounts_table.setHorizontalHeaderLabels(headers) def _format_status_text(self, status: str) -> str: """Formatiert den Status-Text für die Tabelle""" status_texts = { "active": "🟢 Funktioniert", "inactive": "🔴 Problem" } return status_texts.get(status, "🟢 Funktioniert") # Standard: grün def _get_status_tooltip(self, status: str) -> str: """Erstellt Tooltip-Text für den Status""" status_tooltips = { "active": "Account funktioniert normal - letzter Check erfolgreich", "inactive": "Problem: Account gesperrt, eingeschränkt oder Aktion erforderlich" } return status_tooltips.get(status, "Account funktioniert normal")