mirror of
https://github.com/iDescriptor/iDescriptor.git
synced 2026-06-22 03:45:51 +08:00
implement settings, fix bugs and enhance ui
- Added new settings keys in SettingsManager for download path, auto-check updates, auto-raise window, switch to new device, unmount iFuse on exit, theme, and connection timeout. - Implemented methods to get and set these new settings. - Updated SettingsWidget to include UI elements for the new settings, including checkboxes and a combo box for theme selection. - Refactored loadSettings and saveSettings methods to handle new settings. - Removed deprecated settings UI elements to streamline the interface. - Introduced VirtualLocation widget for managing virtual location settings with a map interface. - Integrated QML for map visualization and input handling for latitude and longitude. - Added functionality to apply virtual location settings to the connected device.
This commit is contained in:
@@ -0,0 +1,464 @@
|
||||
#include "exportprogressdialog.h"
|
||||
#include "exportmanager.h"
|
||||
#include "iDescriptor.h"
|
||||
#include <QApplication>
|
||||
#include <QCloseEvent>
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <QDesktopServices>
|
||||
#include <QFileInfo>
|
||||
#include <QHBoxLayout>
|
||||
#include <QMessageBox>
|
||||
#include <QPalette>
|
||||
#include <QStyle>
|
||||
#include <QUrl>
|
||||
|
||||
ExportProgressDialog::ExportProgressDialog(ExportManager *exportManager,
|
||||
QWidget *parent)
|
||||
: QDialog(parent), m_exportManager(exportManager), m_totalItems(0),
|
||||
m_completedItems(0), m_totalBytesTransferred(0),
|
||||
m_lastBytesTransferred(0), m_jobCompleted(false), m_jobCancelled(false)
|
||||
{
|
||||
setupUI();
|
||||
|
||||
// Connect to export manager signals
|
||||
connect(m_exportManager, &ExportManager::exportStarted, this,
|
||||
&ExportProgressDialog::onExportStarted);
|
||||
connect(m_exportManager, &ExportManager::exportProgress, this,
|
||||
&ExportProgressDialog::onExportProgress);
|
||||
connect(m_exportManager, &ExportManager::fileTransferProgress, this,
|
||||
&ExportProgressDialog::onFileTransferProgress);
|
||||
connect(m_exportManager, &ExportManager::itemExported, this,
|
||||
&ExportProgressDialog::onItemExported);
|
||||
connect(m_exportManager, &ExportManager::exportFinished, this,
|
||||
&ExportProgressDialog::onExportFinished);
|
||||
connect(m_exportManager, &ExportManager::exportCancelled, this,
|
||||
&ExportProgressDialog::onExportCancelled);
|
||||
|
||||
// Setup transfer rate timer
|
||||
m_transferRateTimer = new QTimer(this);
|
||||
m_transferRateTimer->setInterval(1000); // Update every second
|
||||
connect(m_transferRateTimer, &QTimer::timeout, this,
|
||||
&ExportProgressDialog::updateTransferRate);
|
||||
|
||||
// Listen for palette changes
|
||||
connect(qApp, &QApplication::paletteChanged, this,
|
||||
&ExportProgressDialog::updateColors);
|
||||
|
||||
updateColors();
|
||||
}
|
||||
|
||||
void ExportProgressDialog::setupUI()
|
||||
{
|
||||
setWindowTitle("Exporting Files");
|
||||
setModal(true);
|
||||
setFixedSize(480, 280);
|
||||
setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::CustomizeWindowHint);
|
||||
|
||||
m_mainLayout = new QVBoxLayout(this);
|
||||
m_mainLayout->setSpacing(16);
|
||||
m_mainLayout->setContentsMargins(24, 24, 24, 24);
|
||||
|
||||
// Title
|
||||
m_titleLabel = new QLabel("Exporting Files");
|
||||
m_titleLabel->setAlignment(Qt::AlignCenter);
|
||||
QFont titleFont = m_titleLabel->font();
|
||||
titleFont.setPointSize(titleFont.pointSize() + 4);
|
||||
titleFont.setWeight(QFont::Medium);
|
||||
m_titleLabel->setFont(titleFont);
|
||||
m_mainLayout->addWidget(m_titleLabel);
|
||||
|
||||
// Status label
|
||||
m_statusLabel = new QLabel("Preparing export...");
|
||||
m_statusLabel->setAlignment(Qt::AlignCenter);
|
||||
m_statusLabel->setWordWrap(true);
|
||||
m_mainLayout->addWidget(m_statusLabel);
|
||||
|
||||
// Current file label
|
||||
m_currentFileLabel = new QLabel();
|
||||
m_currentFileLabel->setAlignment(Qt::AlignCenter);
|
||||
m_currentFileLabel->setWordWrap(true);
|
||||
QFont fileFont = m_currentFileLabel->font();
|
||||
fileFont.setWeight(QFont::Medium);
|
||||
m_currentFileLabel->setFont(fileFont);
|
||||
m_mainLayout->addWidget(m_currentFileLabel);
|
||||
|
||||
// Progress bar
|
||||
m_progressBar = new QProgressBar();
|
||||
m_progressBar->setRange(0, 100);
|
||||
m_progressBar->setValue(0);
|
||||
m_progressBar->setFixedHeight(8);
|
||||
m_progressBar->setTextVisible(false);
|
||||
m_mainLayout->addWidget(m_progressBar);
|
||||
|
||||
// Stats label (items completed)
|
||||
m_statsLabel = new QLabel("0 of 0 items");
|
||||
m_statsLabel->setAlignment(Qt::AlignCenter);
|
||||
m_mainLayout->addWidget(m_statsLabel);
|
||||
|
||||
// Transfer rate
|
||||
m_transferRateLabel = new QLabel();
|
||||
m_transferRateLabel->setAlignment(Qt::AlignCenter);
|
||||
m_mainLayout->addWidget(m_transferRateLabel);
|
||||
|
||||
// Time remaining
|
||||
m_timeRemainingLabel = new QLabel();
|
||||
m_timeRemainingLabel->setAlignment(Qt::AlignCenter);
|
||||
m_mainLayout->addWidget(m_timeRemainingLabel);
|
||||
|
||||
// Add stretch before buttons
|
||||
m_mainLayout->addStretch();
|
||||
|
||||
// Buttons layout
|
||||
QHBoxLayout *buttonLayout = new QHBoxLayout();
|
||||
buttonLayout->addStretch();
|
||||
|
||||
m_cancelButton = new QPushButton("Cancel");
|
||||
m_cancelButton->setFixedSize(80, 32);
|
||||
connect(m_cancelButton, &QPushButton::clicked, this,
|
||||
&ExportProgressDialog::onCancelClicked);
|
||||
buttonLayout->addWidget(m_cancelButton);
|
||||
|
||||
m_closeButton = new QPushButton("Close");
|
||||
m_closeButton->setFixedSize(80, 32);
|
||||
m_closeButton->setVisible(false);
|
||||
connect(m_closeButton, &QPushButton::clicked, this, &QDialog::accept);
|
||||
buttonLayout->addWidget(m_closeButton);
|
||||
|
||||
m_openDirButton = new QPushButton("Show Files");
|
||||
m_openDirButton->setFixedSize(80, 32);
|
||||
m_openDirButton->setVisible(false);
|
||||
connect(m_openDirButton, &QPushButton::clicked, this,
|
||||
&ExportProgressDialog::onOpenDirectoryClicked);
|
||||
buttonLayout->addWidget(m_openDirButton);
|
||||
|
||||
buttonLayout->addStretch();
|
||||
m_mainLayout->addLayout(buttonLayout);
|
||||
}
|
||||
|
||||
// TODO:
|
||||
void ExportProgressDialog::updateColors()
|
||||
{
|
||||
// QPalette palette = qApp->palette();
|
||||
|
||||
// Apply Apple-style colors
|
||||
// QString dialogStyle =
|
||||
// QString("QDialog {"
|
||||
// " background-color: %1;"
|
||||
// " border-radius: 12px;"
|
||||
// "}"
|
||||
// "QLabel {"
|
||||
// " color: %2;"
|
||||
// "}"
|
||||
// "QProgressBar {"
|
||||
// " border: none;"
|
||||
// " border-radius: 4px;"
|
||||
// " background-color: %3;"
|
||||
// "}"
|
||||
// "QProgressBar::chunk {"
|
||||
// " background-color: %4;"
|
||||
// " border-radius: 4px;"
|
||||
// "}"
|
||||
// "QPushButton {"
|
||||
// " background-color: %5;"
|
||||
// " color: %6;"
|
||||
// " border: 1px solid %7;"
|
||||
// " border-radius: 6px;"
|
||||
// " padding: 6px 12px;"
|
||||
// " font-weight: 500;"
|
||||
// "}"
|
||||
// "QPushButton:hover {"
|
||||
// " background-color: %8;"
|
||||
// "}"
|
||||
// "QPushButton:pressed {"
|
||||
// " background-color: %9;"
|
||||
// "}")
|
||||
// .arg(palette.color(QPalette::Base).name())
|
||||
// .arg(palette.color(QPalette::WindowText).name())
|
||||
// .arg(palette.color(QPalette::AlternateBase).name())
|
||||
// .arg(palette.color(QPalette::Highlight).name())
|
||||
// .arg(palette.color(QPalette::Button).name())
|
||||
// .arg(palette.color(QPalette::ButtonText).name())
|
||||
// .arg(palette.color(QPalette::Mid).name())
|
||||
// .arg(palette.color(QPalette::Button).lighter(110).name())
|
||||
// .arg(palette.color(QPalette::Button).darker(110).name());
|
||||
|
||||
// setStyleSheet(dialogStyle);
|
||||
|
||||
// // Special styling for title
|
||||
// m_titleLabel->setStyleSheet(
|
||||
// QString("color: %1; font-weight: 600;")
|
||||
// .arg(palette.color(QPalette::WindowText).name()));
|
||||
}
|
||||
|
||||
void ExportProgressDialog::showForJob(const QUuid &jobId)
|
||||
{
|
||||
m_currentJobId = jobId;
|
||||
m_jobCompleted = false;
|
||||
m_jobCancelled = false;
|
||||
m_totalBytesTransferred = 0;
|
||||
m_lastBytesTransferred = 0;
|
||||
m_completedItems = 0;
|
||||
|
||||
// Reset UI
|
||||
m_progressBar->setValue(0);
|
||||
m_statusLabel->setText("Preparing export...");
|
||||
m_currentFileLabel->clear();
|
||||
m_statsLabel->setText("0 of 0 items");
|
||||
m_transferRateLabel->clear();
|
||||
m_timeRemainingLabel->clear();
|
||||
m_cancelButton->setVisible(true);
|
||||
m_closeButton->setVisible(false);
|
||||
m_openDirButton->setVisible(false);
|
||||
|
||||
show();
|
||||
raise();
|
||||
activateWindow();
|
||||
}
|
||||
|
||||
void ExportProgressDialog::onExportStarted(const QUuid &jobId, int totalItems,
|
||||
const QString &destinationPath)
|
||||
{
|
||||
if (jobId != m_currentJobId)
|
||||
return;
|
||||
|
||||
m_totalItems = totalItems;
|
||||
m_completedItems = 0;
|
||||
m_destinationPath = destinationPath;
|
||||
m_startTime = QDateTime::currentDateTime();
|
||||
m_lastUpdateTime = m_startTime;
|
||||
|
||||
m_statusLabel->setText(QString("Exporting %1 items to %2")
|
||||
.arg(totalItems)
|
||||
.arg(QFileInfo(destinationPath).baseName()));
|
||||
m_statsLabel->setText(QString("0 of %1 items").arg(totalItems));
|
||||
|
||||
m_transferRateTimer->start();
|
||||
}
|
||||
|
||||
void ExportProgressDialog::onExportProgress(const QUuid &jobId, int currentItem,
|
||||
int totalItems,
|
||||
const QString ¤tFileName)
|
||||
{
|
||||
if (jobId != m_currentJobId)
|
||||
return;
|
||||
|
||||
// Update current file
|
||||
m_currentFileLabel->setText(currentFileName);
|
||||
|
||||
// Update stats
|
||||
m_statsLabel->setText(
|
||||
QString("%1 of %2 items").arg(currentItem).arg(totalItems));
|
||||
}
|
||||
|
||||
void ExportProgressDialog::onFileTransferProgress(const QUuid &jobId,
|
||||
const QString &fileName,
|
||||
qint64 bytesTransferred,
|
||||
qint64 totalFileSize)
|
||||
{
|
||||
if (jobId != m_currentJobId)
|
||||
return;
|
||||
|
||||
// Update progress bar based on current file transfer
|
||||
int progress =
|
||||
totalFileSize > 0 ? (bytesTransferred * 100) / totalFileSize : 0;
|
||||
m_progressBar->setValue(progress);
|
||||
|
||||
// Update transfer info
|
||||
QString transferInfo = QString("%1 / %2")
|
||||
.arg(formatFileSize(bytesTransferred))
|
||||
.arg(formatFileSize(totalFileSize));
|
||||
m_transferRateLabel->setText(transferInfo);
|
||||
}
|
||||
|
||||
void ExportProgressDialog::onItemExported(const QUuid &jobId,
|
||||
const ExportResult &result)
|
||||
{
|
||||
if (jobId != m_currentJobId)
|
||||
return;
|
||||
|
||||
if (result.success) {
|
||||
m_completedItems++;
|
||||
m_totalBytesTransferred += result.bytesTransferred;
|
||||
}
|
||||
}
|
||||
|
||||
void ExportProgressDialog::onExportFinished(const QUuid &jobId,
|
||||
const ExportJobSummary &summary)
|
||||
{
|
||||
if (jobId != m_currentJobId)
|
||||
return;
|
||||
|
||||
m_jobCompleted = true;
|
||||
m_transferRateTimer->stop();
|
||||
|
||||
m_progressBar->setValue(100);
|
||||
m_currentFileLabel->clear();
|
||||
|
||||
QString message;
|
||||
if (summary.failedItems == 0) {
|
||||
message = QString("Successfully exported %1 items")
|
||||
.arg(summary.successfulItems);
|
||||
m_titleLabel->setText("Export Complete");
|
||||
} else {
|
||||
message = QString("Exported %1 items (%2 failed)")
|
||||
.arg(summary.successfulItems)
|
||||
.arg(summary.failedItems);
|
||||
m_titleLabel->setText("Export Completed with Errors");
|
||||
}
|
||||
|
||||
m_statusLabel->setText(message);
|
||||
m_transferRateLabel->setText(
|
||||
QString("Total: %1")
|
||||
.arg(formatFileSize(summary.totalBytesTransferred)));
|
||||
m_timeRemainingLabel->clear();
|
||||
|
||||
// Show close button, hide cancel
|
||||
m_cancelButton->setVisible(false);
|
||||
m_closeButton->setVisible(true);
|
||||
m_openDirButton->setVisible(true);
|
||||
m_closeButton->setDefault(true);
|
||||
m_closeButton->setFocus();
|
||||
}
|
||||
|
||||
void ExportProgressDialog::onExportCancelled(const QUuid &jobId)
|
||||
{
|
||||
if (jobId != m_currentJobId)
|
||||
return;
|
||||
|
||||
m_jobCancelled = true;
|
||||
m_transferRateTimer->stop();
|
||||
|
||||
m_titleLabel->setText("Export Cancelled");
|
||||
m_statusLabel->setText("Export was cancelled by user");
|
||||
m_currentFileLabel->clear();
|
||||
m_transferRateLabel->clear();
|
||||
m_timeRemainingLabel->clear();
|
||||
|
||||
// Show close button, hide cancel
|
||||
m_cancelButton->setVisible(false);
|
||||
m_closeButton->setVisible(true);
|
||||
m_closeButton->setDefault(true);
|
||||
m_closeButton->setFocus();
|
||||
}
|
||||
|
||||
void ExportProgressDialog::onCancelClicked()
|
||||
{
|
||||
int reply = QMessageBox::question(
|
||||
this, "Cancel Export", "Are you sure you want to cancel the export?",
|
||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
||||
|
||||
if (reply == QMessageBox::Yes) {
|
||||
m_exportManager->cancelExport(m_currentJobId);
|
||||
m_cancelButton->setEnabled(false);
|
||||
m_cancelButton->setText("Cancelling...");
|
||||
}
|
||||
}
|
||||
|
||||
void ExportProgressDialog::onOpenDirectoryClicked()
|
||||
{
|
||||
if (!m_destinationPath.isEmpty()) {
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(m_destinationPath));
|
||||
}
|
||||
}
|
||||
|
||||
void ExportProgressDialog::updateTransferRate()
|
||||
{
|
||||
if (m_jobCompleted || m_jobCancelled) {
|
||||
return;
|
||||
}
|
||||
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
qint64 elapsed = m_lastUpdateTime.msecsTo(now);
|
||||
|
||||
if (elapsed > 0) {
|
||||
qint64 bytesDiff = m_totalBytesTransferred - m_lastBytesTransferred;
|
||||
qint64 bytesPerSecond = (bytesDiff * 1000) / elapsed;
|
||||
|
||||
m_transferRateLabel->setText(formatTransferRate(bytesPerSecond));
|
||||
|
||||
// Calculate time remaining
|
||||
if (bytesPerSecond > 0 && m_completedItems > 0) {
|
||||
qint64 avgBytesPerItem = m_totalBytesTransferred / m_completedItems;
|
||||
qint64 remainingBytes =
|
||||
(m_totalItems - m_completedItems) * avgBytesPerItem;
|
||||
int secondsRemaining =
|
||||
static_cast<int>(remainingBytes / bytesPerSecond);
|
||||
|
||||
if (secondsRemaining > 0 &&
|
||||
secondsRemaining < 3600) { // Only show if less than 1 hour
|
||||
m_timeRemainingLabel->setText(
|
||||
formatTimeRemaining(secondsRemaining));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_lastBytesTransferred = m_totalBytesTransferred;
|
||||
m_lastUpdateTime = now;
|
||||
}
|
||||
|
||||
void ExportProgressDialog::changeEvent(QEvent *event)
|
||||
{
|
||||
if (event->type() == QEvent::PaletteChange) {
|
||||
updateColors();
|
||||
}
|
||||
QDialog::changeEvent(event);
|
||||
}
|
||||
|
||||
void ExportProgressDialog::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
if (!m_jobCompleted && !m_jobCancelled) {
|
||||
// Ask user if they want to cancel the ongoing export
|
||||
int reply = QMessageBox::question(
|
||||
this, "Export in Progress",
|
||||
"An export is currently in progress. Do you want to cancel it?",
|
||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
||||
|
||||
if (reply == QMessageBox::Yes) {
|
||||
m_exportManager->cancelExport(m_currentJobId);
|
||||
event->accept();
|
||||
} else {
|
||||
event->ignore();
|
||||
}
|
||||
} else {
|
||||
event->accept();
|
||||
}
|
||||
}
|
||||
|
||||
QString ExportProgressDialog::formatFileSize(qint64 bytes) const
|
||||
{
|
||||
const qint64 KB = 1024;
|
||||
const qint64 MB = KB * 1024;
|
||||
const qint64 GB = MB * 1024;
|
||||
|
||||
if (bytes >= GB) {
|
||||
return QString("%1 GB").arg(
|
||||
QString::number(bytes / double(GB), 'f', 2));
|
||||
} else if (bytes >= MB) {
|
||||
return QString("%1 MB").arg(
|
||||
QString::number(bytes / double(MB), 'f', 1));
|
||||
} else if (bytes >= KB) {
|
||||
return QString("%1 KB").arg(
|
||||
QString::number(bytes / double(KB), 'f', 0));
|
||||
} else {
|
||||
return QString("%1 bytes").arg(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
QString ExportProgressDialog::formatTransferRate(qint64 bytesPerSecond) const
|
||||
{
|
||||
return QString("%1/s").arg(formatFileSize(bytesPerSecond));
|
||||
}
|
||||
|
||||
QString ExportProgressDialog::formatTimeRemaining(int secondsRemaining) const
|
||||
{
|
||||
if (secondsRemaining < 60) {
|
||||
return QString("%1 seconds remaining").arg(secondsRemaining);
|
||||
} else {
|
||||
int minutes = secondsRemaining / 60;
|
||||
int seconds = secondsRemaining % 60;
|
||||
return QString("%1:%2 remaining")
|
||||
.arg(minutes)
|
||||
.arg(seconds, 2, 10, QLatin1Char('0'));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user