mirror of
https://github.com/KenanZhu/AutoLibrary.git
synced 2026-06-18 23:43:02 +08:00
feat(gui): 新增 ALStatusLabel 状态标签组件和浏览器驱动下载对话框
This commit is contained in:
@@ -0,0 +1,246 @@
|
|||||||
|
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
from PySide6.QtWidgets import (
|
||||||
|
QLabel
|
||||||
|
)
|
||||||
|
from PySide6.QtCore import (
|
||||||
|
Qt, Property, QPropertyAnimation, QEasingCurve
|
||||||
|
)
|
||||||
|
from PySide6.QtGui import (
|
||||||
|
QPainter, QColor, QConicalGradient, QPalette
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ALStatusLabel(QLabel):
|
||||||
|
|
||||||
|
class Status(Enum):
|
||||||
|
"""
|
||||||
|
Enum class for representing the status of ALStatusLabel.
|
||||||
|
"""
|
||||||
|
|
||||||
|
WAITING = 0
|
||||||
|
RUNNING = 1
|
||||||
|
SUCCESS = 2
|
||||||
|
WARNING = 3
|
||||||
|
FAILURE = 4
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
parent = None
|
||||||
|
):
|
||||||
|
|
||||||
|
super().__init__(parent)
|
||||||
|
self.__status = self.Status.WAITING
|
||||||
|
self.__icon_angle = 0
|
||||||
|
|
||||||
|
self.setupUi()
|
||||||
|
|
||||||
|
|
||||||
|
def setupUi(
|
||||||
|
self
|
||||||
|
):
|
||||||
|
|
||||||
|
self.setFixedSize(36, 36)
|
||||||
|
self.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||||
|
|
||||||
|
self.RunningAnimation = QPropertyAnimation(self, b"iconAngle")
|
||||||
|
self.RunningAnimation.setDuration(1000)
|
||||||
|
self.RunningAnimation.setStartValue(0)
|
||||||
|
self.RunningAnimation.setEndValue(-360)
|
||||||
|
self.RunningAnimation.setLoopCount(-1)
|
||||||
|
self.RunningAnimation.setEasingCurve(QEasingCurve.Type.Linear)
|
||||||
|
|
||||||
|
|
||||||
|
def isDarkMode(
|
||||||
|
self
|
||||||
|
) -> bool:
|
||||||
|
|
||||||
|
return self.palette().color(QPalette.ColorRole.Window).value() < 128
|
||||||
|
|
||||||
|
|
||||||
|
def getMarkColor(
|
||||||
|
self
|
||||||
|
) -> QColor:
|
||||||
|
|
||||||
|
return QColor("#FFFFFF") if self.isDarkMode() else QColor("#454545")
|
||||||
|
|
||||||
|
@Property(Status)
|
||||||
|
def status(
|
||||||
|
self
|
||||||
|
) -> Status:
|
||||||
|
|
||||||
|
return self.__status
|
||||||
|
|
||||||
|
@Property(int)
|
||||||
|
def iconAngle(
|
||||||
|
self
|
||||||
|
) -> int:
|
||||||
|
|
||||||
|
return self.__icon_angle
|
||||||
|
|
||||||
|
@status.setter
|
||||||
|
def status(
|
||||||
|
self,
|
||||||
|
status: Status
|
||||||
|
):
|
||||||
|
|
||||||
|
if status not in self.Status:
|
||||||
|
raise ValueError(f"Invalid (class)Status[enum.Enum] value: {status}")
|
||||||
|
self.__status = status
|
||||||
|
if self.__status == self.Status.RUNNING:
|
||||||
|
self.RunningAnimation.start()
|
||||||
|
else:
|
||||||
|
self.RunningAnimation.stop()
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
@iconAngle.setter
|
||||||
|
def iconAngle(
|
||||||
|
self,
|
||||||
|
value: int
|
||||||
|
):
|
||||||
|
|
||||||
|
self.__icon_angle = value
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
|
||||||
|
def paintEvent(
|
||||||
|
self,
|
||||||
|
event
|
||||||
|
):
|
||||||
|
|
||||||
|
painter = QPainter(self)
|
||||||
|
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
|
||||||
|
center_x = self.width()/2
|
||||||
|
center_y = self.height()/2
|
||||||
|
radius = min(center_x, center_y) - 3
|
||||||
|
match self.__status:
|
||||||
|
case self.Status.WAITING:
|
||||||
|
pen = painter.pen()
|
||||||
|
pen.setWidth(2)
|
||||||
|
pen.setBrush(Qt.BrushStyle.NoBrush)
|
||||||
|
pen.setCapStyle(Qt.PenCapStyle.RoundCap)
|
||||||
|
pen.setColor(QColor("#969696")) # grey
|
||||||
|
painter.setPen(pen)
|
||||||
|
painter.drawEllipse(
|
||||||
|
int(center_x - radius),
|
||||||
|
int(center_y - radius),
|
||||||
|
int(radius*2),
|
||||||
|
int(radius*2)
|
||||||
|
)
|
||||||
|
case self.Status.RUNNING:
|
||||||
|
gradient = QConicalGradient(center_x, center_y, self.__icon_angle)
|
||||||
|
gradient.setColorAt(0.0, QColor("#2294FF" if self.isDarkMode() else "#0094FF"))
|
||||||
|
gradient.setColorAt(1.0, QColor("#2294FF00"))
|
||||||
|
pen = painter.pen()
|
||||||
|
pen.setWidth(3)
|
||||||
|
pen.setBrush(gradient)
|
||||||
|
pen.setCapStyle(Qt.PenCapStyle.RoundCap)
|
||||||
|
painter.setPen(pen)
|
||||||
|
painter.drawEllipse(
|
||||||
|
int(center_x - radius),
|
||||||
|
int(center_y - radius),
|
||||||
|
int(radius*2),
|
||||||
|
int(radius*2)
|
||||||
|
)
|
||||||
|
case self.Status.SUCCESS:
|
||||||
|
# draw the success green circle
|
||||||
|
pen = painter.pen()
|
||||||
|
pen.setWidth(2)
|
||||||
|
pen.setBrush(Qt.BrushStyle.NoBrush)
|
||||||
|
pen.setCapStyle(Qt.PenCapStyle.RoundCap)
|
||||||
|
pen.setColor(QColor("#4CAF50" if self.isDarkMode() else "#00AF50")) # green
|
||||||
|
painter.setPen(pen)
|
||||||
|
painter.drawEllipse(
|
||||||
|
int(center_x - radius),
|
||||||
|
int(center_y - radius),
|
||||||
|
int(radius*2),
|
||||||
|
int(radius*2)
|
||||||
|
)
|
||||||
|
# draw the success check mark '✓'
|
||||||
|
painter.setPen(Qt.PenStyle.SolidLine)
|
||||||
|
pen = painter.pen()
|
||||||
|
pen.setWidth(3)
|
||||||
|
pen.setBrush(Qt.BrushStyle.NoBrush)
|
||||||
|
pen.setCapStyle(Qt.PenCapStyle.RoundCap)
|
||||||
|
# white when dark mode, black when light mode
|
||||||
|
pen.setColor(self.getMarkColor())
|
||||||
|
painter.setPen(pen)
|
||||||
|
mark_size = radius/2
|
||||||
|
mark_path = [
|
||||||
|
(center_x - mark_size, center_y),
|
||||||
|
(center_x - mark_size/3, center_y + mark_size/2),
|
||||||
|
(center_x + mark_size, center_y - mark_size/2)
|
||||||
|
]
|
||||||
|
painter.drawLine(
|
||||||
|
int(mark_path[0][0]),int(mark_path[0][1]),
|
||||||
|
int(mark_path[1][0]),int(mark_path[1][1])
|
||||||
|
)
|
||||||
|
painter.drawLine(
|
||||||
|
int(mark_path[1][0]),int(mark_path[1][1]),
|
||||||
|
int(mark_path[2][0]),int(mark_path[2][1])
|
||||||
|
)
|
||||||
|
case self.Status.WARNING:
|
||||||
|
# draw the warning orange circle
|
||||||
|
pen = painter.pen()
|
||||||
|
pen.setWidth(2)
|
||||||
|
pen.setBrush(Qt.BrushStyle.NoBrush)
|
||||||
|
pen.setCapStyle(Qt.PenCapStyle.RoundCap)
|
||||||
|
pen.setColor(QColor("#FF9800")) # orange
|
||||||
|
painter.setPen(pen)
|
||||||
|
painter.drawEllipse(
|
||||||
|
int(center_x - radius),
|
||||||
|
int(center_y - radius),
|
||||||
|
int(radius*2),
|
||||||
|
int(radius*2)
|
||||||
|
)
|
||||||
|
# draw the warning exclamation mark '!'
|
||||||
|
painter.setPen(Qt.PenStyle.SolidLine)
|
||||||
|
pen = painter.pen()
|
||||||
|
pen.setWidth(3)
|
||||||
|
pen.setBrush(Qt.BrushStyle.NoBrush)
|
||||||
|
pen.setCapStyle(Qt.PenCapStyle.RoundCap)
|
||||||
|
# white when dark mode, black when light mode
|
||||||
|
pen.setColor(self.getMarkColor())
|
||||||
|
painter.setPen(pen)
|
||||||
|
painter.drawLine(
|
||||||
|
int(center_x), int(center_y - radius/2),
|
||||||
|
int(center_x), int(center_y + radius/6)
|
||||||
|
)
|
||||||
|
painter.drawPoint(
|
||||||
|
int(center_x), int(center_y + radius/2)
|
||||||
|
)
|
||||||
|
case self.Status.FAILURE:
|
||||||
|
# draw the failure red circle
|
||||||
|
pen = painter.pen()
|
||||||
|
pen.setWidth(2)
|
||||||
|
pen.setBrush(Qt.BrushStyle.NoBrush)
|
||||||
|
pen.setCapStyle(Qt.PenCapStyle.RoundCap)
|
||||||
|
pen.setColor(QColor("#DC0000")) # red
|
||||||
|
painter.setPen(pen)
|
||||||
|
painter.drawEllipse(
|
||||||
|
int(center_x - radius),
|
||||||
|
int(center_y - radius),
|
||||||
|
int(radius*2),
|
||||||
|
int(radius*2)
|
||||||
|
)
|
||||||
|
# draw the failure cross mark '✗'
|
||||||
|
painter.setPen(Qt.PenStyle.SolidLine)
|
||||||
|
pen = painter.pen()
|
||||||
|
pen.setWidth(3)
|
||||||
|
pen.setBrush(Qt.BrushStyle.NoBrush)
|
||||||
|
pen.setCapStyle(Qt.PenCapStyle.RoundCap)
|
||||||
|
# white when dark mode, black when light mode
|
||||||
|
pen.setColor(self.getMarkColor())
|
||||||
|
painter.setPen(pen)
|
||||||
|
mark_size = radius/3
|
||||||
|
painter.drawLine(
|
||||||
|
int(center_x - mark_size), int(center_y - mark_size),
|
||||||
|
int(center_x + mark_size), int(center_y + mark_size)
|
||||||
|
)
|
||||||
|
painter.drawLine(
|
||||||
|
int(center_x + mark_size), int(center_y - mark_size),
|
||||||
|
int(center_x - mark_size), int(center_y + mark_size)
|
||||||
|
)
|
||||||
|
painter.end()
|
||||||
|
super().paintEvent(event)
|
||||||
@@ -0,0 +1,518 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Copyright (c) 2026 KenanZhu.
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
This software is provided "as is", without any warranty of any kind.
|
||||||
|
You may use, modify, and distribute this file under the terms of the MIT License.
|
||||||
|
See the LICENSE file for details.
|
||||||
|
"""
|
||||||
|
import threading
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from PySide6.QtCore import (
|
||||||
|
Qt, Slot, QThread, Signal
|
||||||
|
)
|
||||||
|
from PySide6.QtWidgets import (
|
||||||
|
QDialog, QLabel, QComboBox, QProgressBar,
|
||||||
|
QPushButton, QVBoxLayout, QHBoxLayout,
|
||||||
|
QMessageBox, QFrame, QLineEdit
|
||||||
|
)
|
||||||
|
from PySide6.QtGui import (
|
||||||
|
QCloseEvent
|
||||||
|
)
|
||||||
|
|
||||||
|
from managers.driver.WebDriverManager import (
|
||||||
|
instance as webdriver_manager_instance,
|
||||||
|
WebDriverManager, WebDriverInfo, WebDriverType
|
||||||
|
)
|
||||||
|
from gui.ALStatusLabel import ALStatusLabel
|
||||||
|
|
||||||
|
|
||||||
|
class DownloadWorker(QThread):
|
||||||
|
"""
|
||||||
|
Worker thread for downloading web drivers.
|
||||||
|
"""
|
||||||
|
|
||||||
|
progress = Signal(float, int, float, str)
|
||||||
|
finished = Signal(object, str)
|
||||||
|
error = Signal(str)
|
||||||
|
cancelled = Signal()
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
driver_manager: WebDriverManager,
|
||||||
|
driver_info: WebDriverInfo
|
||||||
|
):
|
||||||
|
super().__init__()
|
||||||
|
self.__driver_manager = driver_manager
|
||||||
|
self.__driver_info = driver_info
|
||||||
|
self.__driver_path = None
|
||||||
|
self.__cancelled = False
|
||||||
|
self.__cancel_event = threading.Event()
|
||||||
|
|
||||||
|
def cancel(
|
||||||
|
self
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Cancel the download operation.
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.__cancelled = True
|
||||||
|
self.__cancel_event.set()
|
||||||
|
|
||||||
|
def run(
|
||||||
|
self
|
||||||
|
):
|
||||||
|
try:
|
||||||
|
if self.__cancelled:
|
||||||
|
self.cancelled.emit()
|
||||||
|
return
|
||||||
|
self.__driver_path = self.__driver_manager.installDriver(
|
||||||
|
self.__driver_info,
|
||||||
|
progress_callback=self.onProgress,
|
||||||
|
cancel_event=self.__cancel_event
|
||||||
|
)
|
||||||
|
if self.__cancelled:
|
||||||
|
self.cancelled.emit()
|
||||||
|
return
|
||||||
|
if self.__driver_path:
|
||||||
|
self.finished.emit(self.__driver_path, "")
|
||||||
|
else:
|
||||||
|
self.error.emit("下载失败: 未返回有效路径")
|
||||||
|
except Exception as e:
|
||||||
|
if not self.__cancelled:
|
||||||
|
self.error.emit(f"下载失败: {str(e)}")
|
||||||
|
|
||||||
|
def onProgress(
|
||||||
|
self,
|
||||||
|
downloaded: float,
|
||||||
|
total: int,
|
||||||
|
speed: float,
|
||||||
|
message: str
|
||||||
|
):
|
||||||
|
|
||||||
|
if self.__cancel_event.is_set():
|
||||||
|
self.__cancelled = True
|
||||||
|
if not self.__cancelled:
|
||||||
|
self.progress.emit(downloaded, total, speed, message)
|
||||||
|
|
||||||
|
|
||||||
|
class ALWebDriverDownloadDialog(QDialog):
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
parent: Optional[QDialog] = None,
|
||||||
|
driver_dir: str = ""
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Web driver download dialog.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
parent: Parent widget.
|
||||||
|
driver_dir: Driver directory path.
|
||||||
|
"""
|
||||||
|
|
||||||
|
super().__init__(parent)
|
||||||
|
|
||||||
|
self.__driver_dir = driver_dir
|
||||||
|
self.__driver_manager: Optional[WebDriverManager] = None
|
||||||
|
self.__confirmed = False
|
||||||
|
self.__selected_driver_info: Optional[WebDriverInfo] = None
|
||||||
|
self.__driver_infos: list[WebDriverInfo] = []
|
||||||
|
self.__download_thread: Optional[DownloadWorker] = None
|
||||||
|
|
||||||
|
self.setupUi()
|
||||||
|
self.connectSignals()
|
||||||
|
self.initializeDriverManager()
|
||||||
|
self.refreshDriverList()
|
||||||
|
|
||||||
|
def showEvent(
|
||||||
|
self,
|
||||||
|
event
|
||||||
|
):
|
||||||
|
|
||||||
|
result = super().showEvent(event)
|
||||||
|
if self.parent():
|
||||||
|
screen_rect = self.screen().geometry()
|
||||||
|
target_pos = self.parent().geometry().center()
|
||||||
|
target_pos.setX(target_pos.x() - self.width()//2)
|
||||||
|
target_pos.setY(target_pos.y() - self.height()//2)
|
||||||
|
if target_pos.x() < 0:
|
||||||
|
target_pos.setX(0)
|
||||||
|
if target_pos.x() + self.width() > screen_rect.width():
|
||||||
|
target_pos.setX(screen_rect.width() - self.width())
|
||||||
|
if target_pos.y() < 0:
|
||||||
|
target_pos.setY(0)
|
||||||
|
if target_pos.y() + self.height() > screen_rect.height():
|
||||||
|
target_pos.setY(screen_rect.height() - self.height())
|
||||||
|
self.move(target_pos)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def setupUi(
|
||||||
|
self
|
||||||
|
):
|
||||||
|
|
||||||
|
self.setModal(True)
|
||||||
|
self.setMaximumHeight(240)
|
||||||
|
self.setMinimumHeight(240)
|
||||||
|
self.setWindowTitle("浏览器驱动下载 - AutoLibrary")
|
||||||
|
|
||||||
|
self.MainLayout = QVBoxLayout(self)
|
||||||
|
self.MainLayout.setContentsMargins(5, 5, 5, 5)
|
||||||
|
self.MainLayout.setSpacing(5)
|
||||||
|
|
||||||
|
self.BrowserCountLabel = QLabel("检测到 0 个可用浏览器:")
|
||||||
|
self.MainLayout.addWidget(self.BrowserCountLabel)
|
||||||
|
|
||||||
|
self.DriverInfoLayout = QHBoxLayout()
|
||||||
|
self.DriverInfoLayout.setSpacing(5)
|
||||||
|
self.DriverComboBox = QComboBox()
|
||||||
|
self.DriverInfoLayout.addWidget(self.DriverComboBox)
|
||||||
|
self.StatusLabel = ALStatusLabel()
|
||||||
|
self.StatusLabel.setFixedSize(32, 32)
|
||||||
|
self.DriverInfoLayout.addWidget(self.StatusLabel)
|
||||||
|
self.MainLayout.addLayout(self.DriverInfoLayout)
|
||||||
|
|
||||||
|
self.DetailLayout = QVBoxLayout()
|
||||||
|
self.DetailLayout.setSpacing(5)
|
||||||
|
self.DetailLayout.setContentsMargins(5, 5, 5, 5)
|
||||||
|
self.BrowserTypeLabel = QLabel("类型:")
|
||||||
|
self.DetailLayout.addWidget(self.BrowserTypeLabel)
|
||||||
|
self.VersionLabel = QLabel("版本:")
|
||||||
|
self.DetailLayout.addWidget(self.VersionLabel)
|
||||||
|
self.PathLabel = QLineEdit()
|
||||||
|
self.PathLabel.setReadOnly(True)
|
||||||
|
self.PathLabel.setText("路径:未安装")
|
||||||
|
self.DetailLayout.addWidget(self.PathLabel)
|
||||||
|
self.MainLayout.addLayout(self.DetailLayout)
|
||||||
|
|
||||||
|
self.Line = QFrame()
|
||||||
|
self.Line.setFrameShape(QFrame.Shape.HLine)
|
||||||
|
self.Line.setFrameShadow(QFrame.Shadow.Sunken)
|
||||||
|
self.MainLayout.addWidget(self.Line)
|
||||||
|
self.ProgressBar = QProgressBar()
|
||||||
|
self.ProgressBar.setValue(0)
|
||||||
|
self.ProgressBar.setTextVisible(False)
|
||||||
|
self.MainLayout.addWidget(self.ProgressBar)
|
||||||
|
self.ProgressText = QLabel("")
|
||||||
|
self.ProgressText.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||||
|
self.MainLayout.addWidget(self.ProgressText)
|
||||||
|
self.ControlLayout = QHBoxLayout()
|
||||||
|
self.ControlLayout.setSpacing(8)
|
||||||
|
self.ControlLayout.setAlignment(Qt.AlignmentFlag.AlignRight)
|
||||||
|
self.RefreshButton = QPushButton("刷新")
|
||||||
|
self.RefreshButton.setFixedSize(80, 25)
|
||||||
|
self.DownloadButton = QPushButton("下载驱动")
|
||||||
|
self.DownloadButton.setFixedSize(80, 25)
|
||||||
|
self.DeleteButton = QPushButton("删除驱动")
|
||||||
|
self.DeleteButton.setFixedSize(80, 25)
|
||||||
|
self.CancelButton = QPushButton("取消")
|
||||||
|
self.CancelButton.setFixedSize(80, 25)
|
||||||
|
self.ConfirmButton = QPushButton("确认")
|
||||||
|
self.ConfirmButton.setFixedSize(80, 25)
|
||||||
|
self.ConfirmButton.setEnabled(False)
|
||||||
|
|
||||||
|
self.ControlLayout.addWidget(self.RefreshButton)
|
||||||
|
self.ControlLayout.addWidget(self.DownloadButton)
|
||||||
|
self.ControlLayout.addWidget(self.DeleteButton)
|
||||||
|
self.ControlLayout.addWidget(self.CancelButton)
|
||||||
|
self.ControlLayout.addWidget(self.ConfirmButton)
|
||||||
|
self.MainLayout.addLayout(self.ControlLayout)
|
||||||
|
|
||||||
|
|
||||||
|
def connectSignals(
|
||||||
|
self
|
||||||
|
):
|
||||||
|
|
||||||
|
self.RefreshButton.clicked.connect(self.onRefreshButtonClicked)
|
||||||
|
self.DownloadButton.clicked.connect(self.onDownloadButtonClicked)
|
||||||
|
self.DeleteButton.clicked.connect(self.onDeleteButtonClicked)
|
||||||
|
self.CancelButton.clicked.connect(self.onCancelButtonClicked)
|
||||||
|
self.ConfirmButton.clicked.connect(self.onConfirmButtonClicked)
|
||||||
|
self.DriverComboBox.currentIndexChanged.connect(self.onDriverComboBoxChanged)
|
||||||
|
|
||||||
|
|
||||||
|
def initializeDriverManager(
|
||||||
|
self
|
||||||
|
):
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.__driver_manager = webdriver_manager_instance(self.__driver_dir)
|
||||||
|
except ValueError as e:
|
||||||
|
QMessageBox.warning(self, "初始化失败", f"WebDriverManager 初始化失败:\n{str(e)}")
|
||||||
|
self.reject()
|
||||||
|
|
||||||
|
|
||||||
|
def refreshDriverList(
|
||||||
|
self
|
||||||
|
):
|
||||||
|
|
||||||
|
if not self.__driver_manager:
|
||||||
|
return
|
||||||
|
self.__driver_manager.refresh()
|
||||||
|
self.__driver_infos = self.__driver_manager.getDriverInfos()
|
||||||
|
self.DriverComboBox.clear()
|
||||||
|
for driver_info in self.__driver_infos:
|
||||||
|
display_text = f"{driver_info.driver_type.value} - {driver_info.browser_version}"
|
||||||
|
self.DriverComboBox.addItem(display_text)
|
||||||
|
count = len(self.__driver_infos)
|
||||||
|
self.BrowserCountLabel.setText(f"检测到 {count} 个可用浏览器:")
|
||||||
|
if self.__driver_infos:
|
||||||
|
self.onDriverComboBoxChanged(0)
|
||||||
|
|
||||||
|
|
||||||
|
def onDriverComboBoxChanged(
|
||||||
|
self,
|
||||||
|
index: int
|
||||||
|
):
|
||||||
|
|
||||||
|
if not self.__driver_infos or index < 0 or index >= len(self.__driver_infos):
|
||||||
|
return
|
||||||
|
driver_info = self.__driver_infos[index]
|
||||||
|
self.updateDriverInfoDisplay(driver_info)
|
||||||
|
self.updateButtonStates(driver_info)
|
||||||
|
|
||||||
|
|
||||||
|
@Slot()
|
||||||
|
def onRefreshButtonClicked(
|
||||||
|
self
|
||||||
|
):
|
||||||
|
|
||||||
|
self.refreshDriverList()
|
||||||
|
|
||||||
|
|
||||||
|
@Slot()
|
||||||
|
def onDeleteButtonClicked(
|
||||||
|
self
|
||||||
|
):
|
||||||
|
|
||||||
|
index = self.DriverComboBox.currentIndex()
|
||||||
|
if index < 0 or index >= len(self.__driver_infos):
|
||||||
|
return
|
||||||
|
driver_info = self.__driver_infos[index]
|
||||||
|
if driver_info.driver_status.name != "INSTALLED":
|
||||||
|
QMessageBox.information(self, "提示 - AutoLibrary", "该驱动未安装, 无需删除")
|
||||||
|
return
|
||||||
|
reply = QMessageBox.question(
|
||||||
|
self,
|
||||||
|
"确认删除 - AutoLibrary",
|
||||||
|
f"确定要删除 {driver_info.driver_type.value} 驱动吗 ?",
|
||||||
|
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
|
||||||
|
)
|
||||||
|
if reply == QMessageBox.StandardButton.No:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
self.__driver_manager.uninstallDriver(driver_info)
|
||||||
|
self.refreshDriverList()
|
||||||
|
QMessageBox.information(self, "删除成功 - AutoLibrary", "驱动已成功删除")
|
||||||
|
except Exception as e:
|
||||||
|
QMessageBox.critical(self, "删除失败 - AutoLibrary", f"删除驱动时出错:\n{str(e)}")
|
||||||
|
|
||||||
|
@Slot()
|
||||||
|
def onDownloadButtonClicked(
|
||||||
|
self
|
||||||
|
):
|
||||||
|
|
||||||
|
index = self.DriverComboBox.currentIndex()
|
||||||
|
if index < 0 or index >= len(self.__driver_infos):
|
||||||
|
return
|
||||||
|
driver_info = self.__driver_infos[index]
|
||||||
|
if driver_info.driver_status.name == "INSTALLED":
|
||||||
|
return
|
||||||
|
self.StatusLabel.status = ALStatusLabel.Status.RUNNING
|
||||||
|
self.DownloadButton.setEnabled(False)
|
||||||
|
self.RefreshButton.setEnabled(False)
|
||||||
|
self.DriverComboBox.setEnabled(False)
|
||||||
|
self.ProgressBar.setValue(0)
|
||||||
|
self.ProgressText.setText("正在下载驱动...")
|
||||||
|
self.__download_thread = DownloadWorker(self.__driver_manager, driver_info)
|
||||||
|
self.__download_thread.progress.connect(self.onDownloadProgress)
|
||||||
|
self.__download_thread.finished.connect(self.onDownloadFinished)
|
||||||
|
self.__download_thread.error.connect(self.onDownloadError)
|
||||||
|
self.__download_thread.cancelled.connect(self.onDownloadCancelled)
|
||||||
|
self.__download_thread.start()
|
||||||
|
|
||||||
|
@Slot()
|
||||||
|
def onDownloadProgress(
|
||||||
|
self,
|
||||||
|
downloaded: float,
|
||||||
|
total: int,
|
||||||
|
speed: float,
|
||||||
|
message: str
|
||||||
|
):
|
||||||
|
|
||||||
|
progress = downloaded
|
||||||
|
self.ProgressBar.setValue(progress)
|
||||||
|
if speed >= 1024:
|
||||||
|
speed_text = f"{speed/1024:.1f} MB/s"
|
||||||
|
else:
|
||||||
|
speed_text = f"{speed:.1f} KB/s"
|
||||||
|
progress_text = f"{message}... {downloaded:.1f}% - {speed_text}"
|
||||||
|
self.ProgressText.setText(progress_text)
|
||||||
|
|
||||||
|
@Slot()
|
||||||
|
def onDownloadFinished(
|
||||||
|
self
|
||||||
|
):
|
||||||
|
|
||||||
|
self.ProgressBar.setValue(100)
|
||||||
|
self.ProgressText.setText("下载完成 !")
|
||||||
|
self.StatusLabel.status = ALStatusLabel.Status.SUCCESS
|
||||||
|
index = self.DriverComboBox.currentIndex()
|
||||||
|
if 0 <= index < len(self.__driver_infos):
|
||||||
|
driver_info = self.__driver_infos[index]
|
||||||
|
self.updateDriverInfoDisplay(driver_info)
|
||||||
|
self.__download_thread = None
|
||||||
|
self.ConfirmButton.setEnabled(True)
|
||||||
|
self.DownloadButton.setEnabled(False)
|
||||||
|
self.RefreshButton.setEnabled(True)
|
||||||
|
self.DriverComboBox.setEnabled(True)
|
||||||
|
self.DeleteButton.setEnabled(True)
|
||||||
|
|
||||||
|
@Slot()
|
||||||
|
def onDownloadError(
|
||||||
|
self,
|
||||||
|
error_message: str
|
||||||
|
):
|
||||||
|
|
||||||
|
self.StatusLabel.status = ALStatusLabel.Status.FAILURE
|
||||||
|
QMessageBox.critical(self, "下载失败 - AutoLibrary", error_message)
|
||||||
|
self.DownloadButton.setEnabled(True)
|
||||||
|
self.RefreshButton.setEnabled(True)
|
||||||
|
self.DriverComboBox.setEnabled(True)
|
||||||
|
self.CancelButton.setEnabled(True)
|
||||||
|
|
||||||
|
|
||||||
|
@Slot()
|
||||||
|
def onDownloadCancelled(
|
||||||
|
self
|
||||||
|
):
|
||||||
|
|
||||||
|
if self.__download_thread:
|
||||||
|
self.__download_thread.wait(3000)
|
||||||
|
self.__download_thread = None
|
||||||
|
index = self.DriverComboBox.currentIndex()
|
||||||
|
if 0 <= index < len(self.__driver_infos):
|
||||||
|
driver_info = self.__driver_infos[index]
|
||||||
|
self.__driver_manager.cancelDriverDownload(driver_info)
|
||||||
|
self.updateDriverInfoDisplay(driver_info)
|
||||||
|
self.ProgressText.setText("下载已取消")
|
||||||
|
self.ProgressBar.setValue(0)
|
||||||
|
self.StatusLabel.status = ALStatusLabel.Status.WAITING
|
||||||
|
self.DownloadButton.setEnabled(True)
|
||||||
|
self.RefreshButton.setEnabled(True)
|
||||||
|
self.DriverComboBox.setEnabled(True)
|
||||||
|
self.CancelButton.setEnabled(True)
|
||||||
|
self.DeleteButton.setEnabled(False)
|
||||||
|
|
||||||
|
|
||||||
|
@Slot()
|
||||||
|
def onConfirmButtonClicked(
|
||||||
|
self
|
||||||
|
):
|
||||||
|
|
||||||
|
index = self.DriverComboBox.currentIndex()
|
||||||
|
if index < 0 or index >= len(self.__driver_infos):
|
||||||
|
return
|
||||||
|
driver_info = self.__driver_infos[index]
|
||||||
|
if driver_info.driver_status.name != "INSTALLED":
|
||||||
|
return
|
||||||
|
self.__selected_driver_info = driver_info
|
||||||
|
self.__confirmed = True
|
||||||
|
self.accept()
|
||||||
|
|
||||||
|
|
||||||
|
@Slot()
|
||||||
|
def onCancelButtonClicked(
|
||||||
|
self
|
||||||
|
):
|
||||||
|
|
||||||
|
if self.__download_thread:
|
||||||
|
reply = QMessageBox.question(
|
||||||
|
self,
|
||||||
|
"确认取消 - AutoLibrary",
|
||||||
|
"正在下载中, 确定要取消下载吗 ?",
|
||||||
|
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
|
||||||
|
)
|
||||||
|
if reply == QMessageBox.StandardButton.Yes:
|
||||||
|
self.__download_thread.cancel()
|
||||||
|
else:
|
||||||
|
self.__confirmed = False
|
||||||
|
self.__selected_driver_info = None
|
||||||
|
self.reject()
|
||||||
|
|
||||||
|
|
||||||
|
def closeEvent(
|
||||||
|
self,
|
||||||
|
event: QCloseEvent
|
||||||
|
):
|
||||||
|
|
||||||
|
if self.__download_thread and self.__download_thread.isRunning():
|
||||||
|
reply = QMessageBox.question(
|
||||||
|
self,
|
||||||
|
"确认关闭 - AutoLibrary",
|
||||||
|
"驱动正在下载中, 确定要取消并关闭对话框吗 ?",
|
||||||
|
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
|
||||||
|
)
|
||||||
|
if reply == QMessageBox.StandardButton.No:
|
||||||
|
event.ignore()
|
||||||
|
return
|
||||||
|
self.__download_thread.cancel()
|
||||||
|
self.__download_thread.wait(5000)
|
||||||
|
if not self.__confirmed:
|
||||||
|
self.__selected_driver_info = None
|
||||||
|
event.accept()
|
||||||
|
super().closeEvent(event)
|
||||||
|
|
||||||
|
|
||||||
|
def getSelectedDriverInfo(
|
||||||
|
self
|
||||||
|
) -> Optional[WebDriverInfo]:
|
||||||
|
|
||||||
|
return self.__selected_driver_info
|
||||||
|
|
||||||
|
|
||||||
|
def updateDriverInfoDisplay(
|
||||||
|
self,
|
||||||
|
driver_info: WebDriverInfo
|
||||||
|
):
|
||||||
|
|
||||||
|
if driver_info.driver_type == WebDriverType.CHROME:
|
||||||
|
driver_type = "Google Chrome"
|
||||||
|
elif driver_info.driver_type == WebDriverType.FIREFOX:
|
||||||
|
driver_type = "Mozilla Firefox"
|
||||||
|
elif driver_info.driver_type == WebDriverType.EDGE:
|
||||||
|
driver_type = "Microsoft Edge"
|
||||||
|
else:
|
||||||
|
driver_type = "未知"
|
||||||
|
self.BrowserTypeLabel.setText(f"类型:{driver_type}")
|
||||||
|
self.VersionLabel.setText(f"版本:{driver_info.driver_version}")
|
||||||
|
if driver_info.driver_path:
|
||||||
|
self.PathLabel.setText(str(driver_info.driver_path))
|
||||||
|
else:
|
||||||
|
self.PathLabel.setText("未安装")
|
||||||
|
match driver_info.driver_status.name:
|
||||||
|
case "NOT_INSTALLED":
|
||||||
|
self.StatusLabel.status = ALStatusLabel.Status.WAITING
|
||||||
|
case "INSTALLED":
|
||||||
|
self.StatusLabel.status = ALStatusLabel.Status.SUCCESS
|
||||||
|
case "DOWNLOADING":
|
||||||
|
self.StatusLabel.status = ALStatusLabel.Status.RUNNING
|
||||||
|
case "ERROR":
|
||||||
|
self.StatusLabel.status = ALStatusLabel.Status.FAILURE
|
||||||
|
|
||||||
|
|
||||||
|
def updateButtonStates(
|
||||||
|
self,
|
||||||
|
driver_info: WebDriverInfo
|
||||||
|
):
|
||||||
|
|
||||||
|
if driver_info.driver_status.name == "INSTALLED":
|
||||||
|
self.DownloadButton.setEnabled(False)
|
||||||
|
self.DeleteButton.setEnabled(True)
|
||||||
|
self.ConfirmButton.setEnabled(True)
|
||||||
|
else:
|
||||||
|
self.DeleteButton.setEnabled(False)
|
||||||
|
self.DownloadButton.setEnabled(True)
|
||||||
|
self.ConfirmButton.setEnabled(False)
|
||||||
Reference in New Issue
Block a user