332 Zeilen
14 KiB
Python
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")
|