Files
AccountForger-neuerUpload/views/tabs/accounts_tab.py
Claude Project Manager 04585e95b6 Initial commit
2025-08-01 23:50:28 +02:00

332 Zeilen
14 KiB
Python

"""
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")