mirror of
https://github.com/iDescriptor/iDescriptor.git
synced 2026-06-21 19:35:49 +08:00
add CableInfoWidget
- Implement CableInfoWidget to display detailed information about connected cables. - Create associated methods for initializing cable info, analyzing data, and updating the UI. - Introduce get_cable_info function to retrieve cable details from the device. - Replace ClickableWidget with iDescriptor-ui.h in DeviceSidebarWidget and ToolboxWidget. - Update ToolboxWidget to include CableInfoWidget as a selectable tool. - Remove unused ClickableWidget header file.
This commit is contained in:
@@ -0,0 +1,310 @@
|
||||
#include "cableinfowidget.h"
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
#include <QScrollArea>
|
||||
#include <QTimer>
|
||||
|
||||
CableInfoWidget::CableInfoWidget(iDescriptorDevice *device, QWidget *parent)
|
||||
: QWidget(parent), m_device(device), m_response(nullptr)
|
||||
{
|
||||
setupUI();
|
||||
initCableInfo();
|
||||
|
||||
// Auto-refresh cable info after UI is set up
|
||||
// QTimer::singleShot(100, this, &CableInfoWidget::refreshCableInfo);
|
||||
}
|
||||
|
||||
void CableInfoWidget::setupUI()
|
||||
{
|
||||
setWindowTitle("Cable Information");
|
||||
m_mainLayout = new QVBoxLayout(this);
|
||||
m_mainLayout->setSpacing(20);
|
||||
m_mainLayout->setContentsMargins(20, 20, 20, 20);
|
||||
|
||||
// Header section
|
||||
QHBoxLayout *headerLayout = new QHBoxLayout();
|
||||
|
||||
m_iconLabel = new QLabel();
|
||||
m_iconLabel->setFixedSize(48, 48);
|
||||
m_iconLabel->setScaledContents(true);
|
||||
m_iconLabel->setAlignment(Qt::AlignCenter);
|
||||
|
||||
m_statusLabel = new QLabel("Analyzing cable...");
|
||||
m_statusLabel->setStyleSheet("QLabel { "
|
||||
"font-size: 18px; "
|
||||
"font-weight: bold; "
|
||||
"color: #333; "
|
||||
"}");
|
||||
|
||||
headerLayout->addWidget(m_iconLabel);
|
||||
headerLayout->addWidget(m_statusLabel, 1);
|
||||
|
||||
m_mainLayout->addLayout(headerLayout);
|
||||
|
||||
// Scroll area to make the info section scrollable
|
||||
QScrollArea *scrollArea = new QScrollArea();
|
||||
scrollArea->setWidgetResizable(true);
|
||||
scrollArea->setFrameShape(QFrame::NoFrame);
|
||||
scrollArea->setStyleSheet("QScrollArea { "
|
||||
"background-color: #f8f9fa; "
|
||||
"border: 1px solid #dee2e6; "
|
||||
"border-radius: 8px; "
|
||||
"}");
|
||||
|
||||
// Info widget that goes inside the scroll area
|
||||
m_infoWidget = new QWidget();
|
||||
m_infoWidget->setStyleSheet("QWidget { "
|
||||
"background: transparent; "
|
||||
"padding: 16px; "
|
||||
"color: #333; "
|
||||
"}");
|
||||
m_infoLayout = new QGridLayout(m_infoWidget);
|
||||
m_infoLayout->setSpacing(12);
|
||||
m_infoLayout->setColumnStretch(1, 1);
|
||||
|
||||
scrollArea->setWidget(m_infoWidget);
|
||||
|
||||
m_mainLayout->addWidget(scrollArea);
|
||||
m_mainLayout->addStretch();
|
||||
}
|
||||
|
||||
void CableInfoWidget::initCableInfo()
|
||||
{
|
||||
if (!m_device || !m_device->device) {
|
||||
m_statusLabel->setText("❌ Device not available");
|
||||
m_statusLabel->setStyleSheet(
|
||||
"QLabel { color: #dc3545; font-size: 18px; font-weight: bold; }");
|
||||
return;
|
||||
}
|
||||
|
||||
m_statusLabel->setText("Analyzing cable...");
|
||||
m_statusLabel->setStyleSheet(
|
||||
"QLabel { color: #6c757d; font-size: 18px; font-weight: bold; }");
|
||||
|
||||
// Get cable info
|
||||
get_cable_info(m_device->device, m_response);
|
||||
|
||||
analyzeCableInfo();
|
||||
updateUI();
|
||||
}
|
||||
|
||||
void CableInfoWidget::analyzeCableInfo()
|
||||
{
|
||||
qDebug() << "Analyzing cable info...";
|
||||
m_cableInfo = CableInfo();
|
||||
|
||||
if (!m_response) {
|
||||
return;
|
||||
}
|
||||
|
||||
PlistNavigator nav(m_response);
|
||||
PlistNavigator ioreg = nav["IORegistry"];
|
||||
|
||||
if (!ioreg.valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_cableInfo.isConnected = true;
|
||||
|
||||
// Check if genuine (Apple manufacturer and valid model info)
|
||||
m_cableInfo.manufacturer = QString::fromStdString(
|
||||
ioreg["IOAccessoryAccessoryManufacturer"].getString());
|
||||
m_cableInfo.modelNumber = QString::fromStdString(
|
||||
ioreg["IOAccessoryAccessoryModelNumber"].getString());
|
||||
m_cableInfo.accessoryName =
|
||||
QString::fromStdString(ioreg["IOAccessoryAccessoryName"].getString());
|
||||
m_cableInfo.serialNumber = QString::fromStdString(
|
||||
ioreg["IOAccessoryAccessorySerialNumber"].getString());
|
||||
m_cableInfo.interfaceModuleSerial = QString::fromStdString(
|
||||
ioreg["IOAccessoryInterfaceModuleSerialNumber"].getString());
|
||||
|
||||
// Determine if genuine based on manufacturer and presence of detailed info
|
||||
m_cableInfo.isGenuine =
|
||||
(m_cableInfo.manufacturer.contains("Apple", Qt::CaseInsensitive) &&
|
||||
!m_cableInfo.modelNumber.isEmpty() &&
|
||||
!m_cableInfo.accessoryName.isEmpty());
|
||||
|
||||
// Check if Type-C (based on accessory name or TriStar class)
|
||||
m_cableInfo.triStarClass =
|
||||
QString::fromStdString(ioreg["TriStarICClass"].getString());
|
||||
m_cableInfo.isTypeC =
|
||||
(m_cableInfo.accessoryName.contains("USB-C", Qt::CaseInsensitive) ||
|
||||
m_cableInfo.triStarClass.contains("1612")); // CBTL1612 is Type-C
|
||||
|
||||
// Power information
|
||||
m_cableInfo.currentLimit = ioreg["IOAccessoryUSBCurrentLimit"].getUInt();
|
||||
m_cableInfo.chargingVoltage =
|
||||
ioreg["IOAccessoryUSBChargingVoltage"].getUInt();
|
||||
|
||||
// Connection type
|
||||
QString connectString = QString::fromStdString(
|
||||
ioreg["IOAccessoryUSBConnectString"].getString());
|
||||
int connectType =
|
||||
static_cast<int>(ioreg["IOAccessoryUSBConnectType"].getUInt());
|
||||
m_cableInfo.connectionType =
|
||||
QString("%1 (Type %2)").arg(connectString).arg(connectType);
|
||||
|
||||
// Supported and active transports
|
||||
PlistNavigator supportedTransports = ioreg["TransportsSupported"];
|
||||
if (supportedTransports.valid() &&
|
||||
plist_get_node_type(supportedTransports) == PLIST_ARRAY) {
|
||||
uint32_t count = plist_array_get_size(supportedTransports);
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
PlistNavigator transport = supportedTransports[static_cast<int>(i)];
|
||||
if (transport.valid()) {
|
||||
m_cableInfo.supportedTransports.append(
|
||||
QString::fromStdString(transport.getString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PlistNavigator activeTransports = ioreg["TransportsActive"];
|
||||
if (activeTransports.valid() &&
|
||||
plist_get_node_type(activeTransports) == PLIST_ARRAY) {
|
||||
uint32_t count = plist_array_get_size(activeTransports);
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
PlistNavigator transport = activeTransports[static_cast<int>(i)];
|
||||
if (transport.valid()) {
|
||||
m_cableInfo.activeTransports.append(
|
||||
QString::fromStdString(transport.getString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CableInfoWidget::updateUI()
|
||||
{
|
||||
// Clear existing info
|
||||
QLayoutItem *item;
|
||||
while ((item = m_infoLayout->takeAt(0)) != nullptr) {
|
||||
delete item->widget();
|
||||
delete item;
|
||||
}
|
||||
|
||||
// if (!m_cableInfo.isConnected) {
|
||||
// m_statusLabel->setText("❌ No cable detected");
|
||||
// m_statusLabel->setStyleSheet(
|
||||
// "QLabel { color: #dc3545; font-size: 18px; font-weight: bold;
|
||||
// }");
|
||||
// m_iconLabel->setText("🔌");
|
||||
// m_iconLabel->setStyleSheet("QLabel { font-size: 32px; }");
|
||||
|
||||
// QLabel *noDataLabel = new QLabel("No cable information available");
|
||||
// noDataLabel->setStyleSheet(
|
||||
// "QLabel { color: #6c757d; font-size: 14px; text-align: center;
|
||||
// }");
|
||||
// m_infoLayout->addWidget(noDataLabel, 0, 0, 1, 2, Qt::AlignCenter);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// Update status and icon based on cable type
|
||||
QString statusText;
|
||||
QString statusStyle;
|
||||
QString iconText;
|
||||
|
||||
if (m_cableInfo.isGenuine) {
|
||||
statusText = QString("Genuine %1")
|
||||
.arg(m_cableInfo.isTypeC ? "USB-C to Lightning Cable"
|
||||
: "Lightning Cable");
|
||||
statusStyle =
|
||||
"QLabel { color: #28a745; font-size: 18px; font-weight: bold; }";
|
||||
iconText = m_cableInfo.isTypeC ? "Type-C" : "Lightning";
|
||||
} else {
|
||||
statusText = "⚠️ Third-party Cable";
|
||||
statusStyle =
|
||||
"QLabel { color: #ffc107; font-size: 18px; font-weight: bold; }";
|
||||
iconText = "❓";
|
||||
}
|
||||
|
||||
m_statusLabel->setText(statusText);
|
||||
m_statusLabel->setStyleSheet(statusStyle);
|
||||
m_iconLabel->setText(iconText);
|
||||
m_iconLabel->setStyleSheet("QLabel { font-size: 32px; }");
|
||||
|
||||
int row = 0;
|
||||
|
||||
// Basic information
|
||||
if (!m_cableInfo.accessoryName.isEmpty()) {
|
||||
createInfoRow(m_infoLayout, row++, "Name:", m_cableInfo.accessoryName);
|
||||
}
|
||||
|
||||
if (!m_cableInfo.manufacturer.isEmpty()) {
|
||||
createInfoRow(m_infoLayout, row++,
|
||||
"Manufacturer:", m_cableInfo.manufacturer);
|
||||
}
|
||||
|
||||
if (!m_cableInfo.modelNumber.isEmpty()) {
|
||||
createInfoRow(m_infoLayout, row++, "Model:", m_cableInfo.modelNumber);
|
||||
}
|
||||
|
||||
if (!m_cableInfo.serialNumber.isEmpty()) {
|
||||
createInfoRow(m_infoLayout, row++,
|
||||
"Serial Number:", m_cableInfo.serialNumber);
|
||||
}
|
||||
|
||||
if (!m_cableInfo.interfaceModuleSerial.isEmpty()) {
|
||||
createInfoRow(m_infoLayout, row++,
|
||||
"Interface Module:", m_cableInfo.interfaceModuleSerial);
|
||||
}
|
||||
|
||||
// Technical information
|
||||
createInfoRow(m_infoLayout, row++, "Cable Type:",
|
||||
m_cableInfo.isTypeC ? "USB-C to Lightning"
|
||||
: "Lightning to USB-A");
|
||||
|
||||
if (m_cableInfo.currentLimit > 0) {
|
||||
createInfoRow(m_infoLayout, row++, "Current Limit:",
|
||||
QString("%1 mA").arg(m_cableInfo.currentLimit));
|
||||
}
|
||||
|
||||
if (m_cableInfo.chargingVoltage > 0) {
|
||||
createInfoRow(m_infoLayout, row++, "Charging Voltage:",
|
||||
QString("%1 mV").arg(m_cableInfo.chargingVoltage));
|
||||
}
|
||||
|
||||
if (!m_cableInfo.connectionType.isEmpty()) {
|
||||
createInfoRow(m_infoLayout, row++,
|
||||
"Connection:", m_cableInfo.connectionType);
|
||||
}
|
||||
|
||||
if (!m_cableInfo.triStarClass.isEmpty()) {
|
||||
createInfoRow(m_infoLayout, row++,
|
||||
"Controller:", m_cableInfo.triStarClass);
|
||||
}
|
||||
|
||||
// Transport information
|
||||
if (!m_cableInfo.activeTransports.isEmpty()) {
|
||||
createInfoRow(m_infoLayout, row++, "Active Transports:",
|
||||
m_cableInfo.activeTransports.join(", "));
|
||||
}
|
||||
|
||||
if (!m_cableInfo.supportedTransports.isEmpty()) {
|
||||
createInfoRow(m_infoLayout, row++, "Supported Transports:",
|
||||
m_cableInfo.supportedTransports.join(", "));
|
||||
}
|
||||
}
|
||||
|
||||
void CableInfoWidget::createInfoRow(QGridLayout *layout, int row,
|
||||
const QString &label, const QString &value,
|
||||
const QString &style)
|
||||
{
|
||||
qDebug() << "Creating info row:" << label << value;
|
||||
QLabel *labelWidget = new QLabel(label);
|
||||
labelWidget->setStyleSheet("QLabel { "
|
||||
"font-weight: bold; "
|
||||
"color: #495057; "
|
||||
"font-size: 13px; "
|
||||
"}");
|
||||
|
||||
QLabel *valueWidget = new QLabel(value);
|
||||
QString valueStyle = style.isEmpty() ? "QLabel { "
|
||||
"color: #212529; "
|
||||
"font-size: 13px; "
|
||||
"}"
|
||||
: style;
|
||||
valueWidget->setStyleSheet(valueStyle);
|
||||
valueWidget->setWordWrap(true);
|
||||
|
||||
layout->addWidget(labelWidget, row, 0, Qt::AlignTop);
|
||||
layout->addWidget(valueWidget, row, 1, Qt::AlignTop);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
#ifndef CABLEINFOWIDGET_H
|
||||
#define CABLEINFOWIDGET_H
|
||||
|
||||
#include "iDescriptor.h"
|
||||
#include <QGridLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QProgressBar>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
#include <plist/plist.h>
|
||||
|
||||
class CableInfoWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CableInfoWidget(iDescriptorDevice *device,
|
||||
QWidget *parent = nullptr);
|
||||
|
||||
private slots:
|
||||
void initCableInfo();
|
||||
|
||||
private:
|
||||
void setupUI();
|
||||
void analyzeCableInfo();
|
||||
void updateUI();
|
||||
void createInfoRow(QGridLayout *layout, int row, const QString &label,
|
||||
const QString &value, const QString &style = "");
|
||||
|
||||
// Cable information structure
|
||||
struct CableInfo {
|
||||
bool isConnected = false;
|
||||
bool isGenuine = false;
|
||||
bool isTypeC = false;
|
||||
QString manufacturer;
|
||||
QString modelNumber;
|
||||
QString accessoryName;
|
||||
QString serialNumber;
|
||||
QString interfaceModuleSerial;
|
||||
uint64_t currentLimit = 0;
|
||||
uint64_t chargingVoltage = 0;
|
||||
QString connectionType;
|
||||
QString triStarClass;
|
||||
QStringList supportedTransports;
|
||||
QStringList activeTransports;
|
||||
};
|
||||
|
||||
// UI components
|
||||
QVBoxLayout *m_mainLayout;
|
||||
QLabel *m_statusLabel;
|
||||
QLabel *m_iconLabel;
|
||||
QWidget *m_infoWidget;
|
||||
QGridLayout *m_infoLayout;
|
||||
|
||||
// Data
|
||||
iDescriptorDevice *m_device;
|
||||
CableInfo m_cableInfo;
|
||||
plist_t m_response;
|
||||
};
|
||||
|
||||
#endif // CABLEINFOWIDGET_H
|
||||
@@ -1,28 +0,0 @@
|
||||
#ifndef CLICKABLEWIDGET_H
|
||||
#define CLICKABLEWIDGET_H
|
||||
|
||||
#include <QMouseEvent>
|
||||
#include <QWidget>
|
||||
|
||||
class ClickableWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ClickableWidget(QWidget *parent = nullptr) : QWidget(parent) {}
|
||||
|
||||
signals:
|
||||
void clicked();
|
||||
|
||||
protected:
|
||||
// Override the protected event handler
|
||||
void mousePressEvent(QMouseEvent *event) override
|
||||
{
|
||||
// When the event happens, emit our public signal
|
||||
emit clicked();
|
||||
// Call the base class implementation if needed
|
||||
QWidget::mousePressEvent(event);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CLICKABLEWIDGET_H
|
||||
@@ -0,0 +1,49 @@
|
||||
#include "../../iDescriptor.h"
|
||||
#include <libimobiledevice/diagnostics_relay.h>
|
||||
#include <libimobiledevice/libimobiledevice.h>
|
||||
#include <plist/plist.h>
|
||||
|
||||
void get_cable_info(idevice_t device, plist_t &response)
|
||||
{
|
||||
lockdownd_client_t lockdown_client = NULL;
|
||||
diagnostics_relay_client_t diagnostics_client = NULL;
|
||||
lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
|
||||
lockdownd_service_descriptor_t service = NULL;
|
||||
int use_network = 0;
|
||||
|
||||
if (LOCKDOWN_E_SUCCESS != (ret = lockdownd_client_new_with_handshake(
|
||||
device, &lockdown_client, TOOL_NAME))) {
|
||||
idevice_free(device);
|
||||
printf("ERROR: Could not connect to lockdownd, error code %d\n", ret);
|
||||
}
|
||||
|
||||
/* attempt to use newer diagnostics service available on iOS 5 and later */
|
||||
ret = lockdownd_start_service(
|
||||
lockdown_client, "com.apple.mobile.diagnostics_relay", &service);
|
||||
if (ret == LOCKDOWN_E_INVALID_SERVICE) {
|
||||
/* attempt to use older diagnostics service */
|
||||
ret = lockdownd_start_service(
|
||||
lockdown_client, "com.apple.iosdiagnostics.relay", &service);
|
||||
}
|
||||
lockdownd_client_free(lockdown_client);
|
||||
|
||||
if (ret != LOCKDOWN_E_SUCCESS) {
|
||||
idevice_free(device);
|
||||
printf("ERROR: Could not start diagnostics relay service: %s\n",
|
||||
lockdownd_strerror(ret));
|
||||
}
|
||||
|
||||
if ((ret == LOCKDOWN_E_SUCCESS) && service && (service->port > 0)) {
|
||||
if (diagnostics_relay_client_new(device, service,
|
||||
&diagnostics_client) !=
|
||||
DIAGNOSTICS_RELAY_E_SUCCESS) {
|
||||
printf("ERROR: Could not connect to diagnostics_relay!\n");
|
||||
}
|
||||
}
|
||||
|
||||
diagnostics_relay_error_t err = diagnostics_relay_query_ioregistry_entry(
|
||||
diagnostics_client, NULL, "AppleTriStarBuiltIn", &response);
|
||||
|
||||
if (diagnostics_client)
|
||||
diagnostics_relay_client_free(diagnostics_client);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "devicesidebarwidget.h"
|
||||
#include "clickablewidget.h"
|
||||
#include "iDescriptor-ui.h"
|
||||
#include "loadingspinnerwidget.h"
|
||||
#include <QDebug>
|
||||
#include <QEasingCurve>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef DEVICESIDEBARWIDGET_H
|
||||
#define DEVICESIDEBARWIDGET_H
|
||||
|
||||
#include "clickablewidget.h"
|
||||
#include "iDescriptor-ui.h"
|
||||
#include <QButtonGroup>
|
||||
#include <QFrame>
|
||||
#include <QHBoxLayout>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
#include <QGraphicsView>
|
||||
#include <QMainWindow>
|
||||
#include <QMouseEvent>
|
||||
#include <QWidget>
|
||||
|
||||
#define COLOR_GREEN QColor(0, 180, 0) // Green
|
||||
#define COLOR_ORANGE QColor(255, 140, 0) // Orange
|
||||
@@ -26,6 +28,49 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
class ClickableWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
using QWidget::QWidget;
|
||||
|
||||
signals:
|
||||
void clicked();
|
||||
|
||||
protected:
|
||||
// On mouse release, if the click is inside the widget, emit the clicked
|
||||
// signal
|
||||
void mouseReleaseEvent(QMouseEvent *event) override
|
||||
{
|
||||
if (event->button() == Qt::LeftButton &&
|
||||
rect().contains(event->pos())) {
|
||||
emit clicked();
|
||||
}
|
||||
QWidget::mouseReleaseEvent(event);
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
void setupMacOSWindow(QMainWindow *window);
|
||||
#endif
|
||||
|
||||
enum class iDescriptorTool {
|
||||
Airplayer,
|
||||
RealtimeScreen,
|
||||
EnterRecoveryMode,
|
||||
MountDevImage,
|
||||
VirtualLocation,
|
||||
Restart,
|
||||
Shutdown,
|
||||
RecoveryMode,
|
||||
QueryMobileGestalt,
|
||||
DeveloperDiskImages,
|
||||
WirelessFileImport,
|
||||
MountIphone,
|
||||
CableInfoWidget,
|
||||
TouchIdTest,
|
||||
FaceIdTest,
|
||||
UnmountDevImage,
|
||||
Unknown,
|
||||
iFuse
|
||||
};
|
||||
@@ -449,3 +449,5 @@ void fetchAppIconFromApple(const QString &bundleId,
|
||||
QObject *context);
|
||||
|
||||
afc_error_t afc2_client_new(idevice_t device, afc_client_t *afc);
|
||||
|
||||
void get_cable_info(idevice_t device, plist_t &response);
|
||||
|
||||
+176
-138
@@ -1,7 +1,9 @@
|
||||
#include "toolboxwidget.h"
|
||||
#include "airplaywindow.h"
|
||||
#include "appcontext.h"
|
||||
#include "cableinfowidget.h"
|
||||
#include "devdiskimageswidget.h"
|
||||
#include "iDescriptor-ui.h"
|
||||
#include "iDescriptor.h"
|
||||
#include "ifusewidget.h"
|
||||
#include "pcfileexplorerwidget.h"
|
||||
@@ -13,6 +15,13 @@
|
||||
#include <QMessageBox>
|
||||
#include <QStyle>
|
||||
|
||||
struct iDescriptorToolWidget {
|
||||
iDescriptorTool tool;
|
||||
QString description;
|
||||
bool requiresDevice;
|
||||
QString iconName;
|
||||
};
|
||||
|
||||
bool enterRecoveryMode(iDescriptorDevice *device)
|
||||
{
|
||||
lockdownd_client_t client = NULL;
|
||||
@@ -100,70 +109,50 @@ void ToolboxWidget::setupUI()
|
||||
m_gridLayout = new QGridLayout(m_contentWidget);
|
||||
m_gridLayout->setSpacing(10);
|
||||
|
||||
// Create toolboxes
|
||||
QWidget *airplayerBox =
|
||||
createToolbox("Airplayer",
|
||||
"Start an airplayer service to cast your device screen "
|
||||
"(does not require a device to be connected)",
|
||||
"SP_MediaPlay", false);
|
||||
QWidget *virtualLocationBox = createToolbox(
|
||||
"Virtual Location", "Simulate GPS location on your device",
|
||||
"SP_DriveNetIcon", true);
|
||||
QWidget *realtimeScreenBox = createToolbox(
|
||||
"Realtime Screen",
|
||||
"View device screen in real-time (wired connection required)",
|
||||
"SP_ComputerIcon", true);
|
||||
QWidget *restartBox = createToolbox("Restart", "Restart device services",
|
||||
"SP_MediaStop", true);
|
||||
QWidget *shutdownBox = createToolbox("Shutdown", "Shut down the device",
|
||||
"SP_MessageBoxWarning", true);
|
||||
QWidget *recoveryBox =
|
||||
createToolbox("Recovery Mode", "Enter device recovery mode",
|
||||
"SP_MessageBoxWarning", true);
|
||||
QWidget *mobileGestaltBox = createToolbox(
|
||||
"Query MobileGestalt", "Query device hardware information",
|
||||
"SP_FileDialogDetailedView", true);
|
||||
QWidget *touchIdBox =
|
||||
createToolbox("Touch ID Test", "Test Touch ID functionality",
|
||||
"SP_DialogOkButton", true);
|
||||
QWidget *faceIdBox =
|
||||
createToolbox("Face ID Test", "Test Face ID functionality",
|
||||
"SP_DialogOkButton", true);
|
||||
QWidget *unmountDevImage =
|
||||
createToolbox("Unmount Dev Image", "Unmount a developer image",
|
||||
"SP_DialogOkButton", true);
|
||||
QWidget *enterRecoveryMode =
|
||||
createToolbox("Enter Recovery Mode", "Enter device recovery mode",
|
||||
"SP_DialogOkButton", true);
|
||||
QList<iDescriptorToolWidget> toolWidgets;
|
||||
toolWidgets.append({iDescriptorTool::Airplayer,
|
||||
"Start an airplayer service to cast your device screen "
|
||||
"(does not require a device to be connected)",
|
||||
false, ""});
|
||||
toolWidgets.append({iDescriptorTool::VirtualLocation,
|
||||
"Simulate GPS location on your device", true, ""});
|
||||
toolWidgets.append(
|
||||
{iDescriptorTool::RealtimeScreen,
|
||||
"View device screen in real-time (wired connection required)", true,
|
||||
""});
|
||||
toolWidgets.append(
|
||||
{iDescriptorTool::Restart, "Restart device services", true, ""});
|
||||
toolWidgets.append(
|
||||
{iDescriptorTool::Shutdown, "Shut down the device", true, ""});
|
||||
toolWidgets.append({iDescriptorTool::RecoveryMode,
|
||||
"Enter device recovery mode", true, ""});
|
||||
toolWidgets.append({iDescriptorTool::QueryMobileGestalt,
|
||||
"Query device hardware information", true, ""});
|
||||
toolWidgets.append({iDescriptorTool::TouchIdTest,
|
||||
"Test Touch ID functionality", true, ""});
|
||||
toolWidgets.append(
|
||||
{iDescriptorTool::FaceIdTest, "Test Face ID functionality", true, ""});
|
||||
toolWidgets.append({iDescriptorTool::UnmountDevImage,
|
||||
"Unmount a developer image", true, ""});
|
||||
toolWidgets.append({iDescriptorTool::EnterRecoveryMode,
|
||||
"Enter device recovery mode", true, ""});
|
||||
toolWidgets.append({iDescriptorTool::DeveloperDiskImages,
|
||||
"Manage developer disk images", false, ""});
|
||||
toolWidgets.append({iDescriptorTool::WirelessFileImport,
|
||||
"Import files wirelessly to your iDevice", false, ""});
|
||||
toolWidgets.append({iDescriptorTool::MountIphone,
|
||||
"Mount your iPhone's filesystem on your PC", true, ""});
|
||||
toolWidgets.append({iDescriptorTool::CableInfoWidget,
|
||||
"View detailed cable and connection info", true, ""});
|
||||
|
||||
QWidget *devDiskImages =
|
||||
createToolbox("Developer Disk Images", "Manage developer disk images",
|
||||
"SP_DialogOkButton", false);
|
||||
|
||||
QWidget *wirelessImport = createToolbox(
|
||||
"Wireless File Import", "Import files wirelessly to your iDevice",
|
||||
"SP_DialogOkButton", false);
|
||||
|
||||
QWidget *mount_iPhone = createToolbox(
|
||||
"Mount iPhone", "Mount your iPhone's filesystem on your PC",
|
||||
"SP_DialogOkButton", false);
|
||||
|
||||
// Add toolboxes to grid (3 columns)
|
||||
m_gridLayout->addWidget(airplayerBox, 0, 0);
|
||||
m_gridLayout->addWidget(virtualLocationBox, 0, 1);
|
||||
m_gridLayout->addWidget(realtimeScreenBox, 0, 2);
|
||||
m_gridLayout->addWidget(restartBox, 1, 0);
|
||||
m_gridLayout->addWidget(shutdownBox, 1, 1);
|
||||
m_gridLayout->addWidget(recoveryBox, 1, 2);
|
||||
m_gridLayout->addWidget(mobileGestaltBox, 2, 0);
|
||||
m_gridLayout->addWidget(touchIdBox, 2, 1);
|
||||
m_gridLayout->addWidget(faceIdBox, 2, 2);
|
||||
m_gridLayout->addWidget(enterRecoveryMode, 3, 0);
|
||||
m_gridLayout->addWidget(unmountDevImage, 3, 1);
|
||||
m_gridLayout->addWidget(devDiskImages, 3, 2);
|
||||
m_gridLayout->addWidget(wirelessImport, 4, 0);
|
||||
m_gridLayout->addWidget(mount_iPhone, 4, 1);
|
||||
m_gridLayout->setRowStretch(3, 1);
|
||||
for (int i = 0; i < toolWidgets.size(); ++i) {
|
||||
const auto &tool = toolWidgets[i];
|
||||
ClickableWidget *toolbox =
|
||||
createToolbox(tool.tool, tool.description, tool.requiresDevice);
|
||||
int row = i / 3;
|
||||
int col = i % 3;
|
||||
m_gridLayout->addWidget(toolbox, row, col);
|
||||
}
|
||||
|
||||
m_scrollArea->setWidget(m_contentWidget);
|
||||
mainLayout->addWidget(m_scrollArea);
|
||||
@@ -172,36 +161,78 @@ void ToolboxWidget::setupUI()
|
||||
this, &ToolboxWidget::onDeviceSelectionChanged);
|
||||
}
|
||||
|
||||
QWidget *ToolboxWidget::createToolbox(const QString &title,
|
||||
const QString &description,
|
||||
const QString &iconName,
|
||||
bool requiresDevice)
|
||||
ClickableWidget *ToolboxWidget::createToolbox(iDescriptorTool tool,
|
||||
const QString &description,
|
||||
bool requiresDevice)
|
||||
{
|
||||
QFrame *frame = new QFrame();
|
||||
frame->setObjectName("toolboxFrame");
|
||||
frame->setFrameStyle(QFrame::Box);
|
||||
frame->setStyleSheet("#toolboxFrame { "
|
||||
"border-radius: 5px; padding: 5px; }");
|
||||
frame->setFixedSize(200, 120);
|
||||
ClickableWidget *b = new ClickableWidget();
|
||||
b->setStyleSheet("padding: 5px; border: none; outline: none;");
|
||||
b->setFixedSize(200, 120);
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout(frame);
|
||||
QVBoxLayout *layout = new QVBoxLayout(b);
|
||||
|
||||
// Icon
|
||||
QLabel *iconLabel = new QLabel();
|
||||
QIcon icon =
|
||||
this->style()->standardIcon(static_cast<QStyle::StandardPixmap>(
|
||||
iconName == "SP_MediaPlay" ? QStyle::SP_MediaPlay
|
||||
: iconName == "SP_DriveNetIcon" ? QStyle::SP_DriveNetIcon
|
||||
: iconName == "SP_ComputerIcon" ? QStyle::SP_ComputerIcon
|
||||
: iconName == "SP_BrowserReload" ? QStyle::SP_BrowserReload
|
||||
: iconName == "SP_MediaStop" ? QStyle::SP_MediaStop
|
||||
: iconName == "SP_MessageBoxWarning" ? QStyle::SP_MessageBoxWarning
|
||||
: iconName == "SP_FileDialogDetailedView"
|
||||
? QStyle::SP_FileDialogDetailedView
|
||||
: QStyle::SP_DialogOkButton));
|
||||
// TODO:icons
|
||||
this->style()->standardIcon(
|
||||
static_cast<QStyle::StandardPixmap>(QStyle::SP_DialogOkButton));
|
||||
iconLabel->setPixmap(icon.pixmap(32, 32));
|
||||
iconLabel->setAlignment(Qt::AlignCenter);
|
||||
|
||||
QString title;
|
||||
switch (tool) {
|
||||
case iDescriptorTool::Airplayer:
|
||||
title = "Airplayer";
|
||||
break;
|
||||
case iDescriptorTool::RealtimeScreen:
|
||||
title = "Realtime Screen";
|
||||
break;
|
||||
case iDescriptorTool::EnterRecoveryMode:
|
||||
title = "Enter Recovery Mode";
|
||||
break;
|
||||
case iDescriptorTool::MountDevImage:
|
||||
title = "Mount Dev Image";
|
||||
break;
|
||||
case iDescriptorTool::VirtualLocation:
|
||||
title = "Virtual Location";
|
||||
break;
|
||||
case iDescriptorTool::Restart:
|
||||
title = "Restart";
|
||||
break;
|
||||
case iDescriptorTool::Shutdown:
|
||||
title = "Shutdown";
|
||||
break;
|
||||
case iDescriptorTool::RecoveryMode:
|
||||
title = "Recovery Mode";
|
||||
break;
|
||||
case iDescriptorTool::QueryMobileGestalt:
|
||||
title = "Query Mobile Gestalt";
|
||||
break;
|
||||
case iDescriptorTool::DeveloperDiskImages:
|
||||
title = "Dev Disk Images";
|
||||
break;
|
||||
case iDescriptorTool::WirelessFileImport:
|
||||
title = "Wireless File Import";
|
||||
break;
|
||||
case iDescriptorTool::MountIphone:
|
||||
title = "iFuse Mount";
|
||||
break;
|
||||
case iDescriptorTool::CableInfoWidget:
|
||||
title = "Cable Info";
|
||||
break;
|
||||
case iDescriptorTool::TouchIdTest:
|
||||
title = "Touch ID Test";
|
||||
break;
|
||||
case iDescriptorTool::FaceIdTest:
|
||||
title = "Face ID Test";
|
||||
break;
|
||||
case iDescriptorTool::UnmountDevImage:
|
||||
title = "Unmount Dev Image";
|
||||
break;
|
||||
default:
|
||||
title = "Unknown Tool";
|
||||
break;
|
||||
}
|
||||
// Title
|
||||
QLabel *titleLabel = new QLabel(title);
|
||||
titleLabel->setFont(QFont("Arial", 10, QFont::Bold));
|
||||
@@ -218,28 +249,13 @@ QWidget *ToolboxWidget::createToolbox(const QString &title,
|
||||
layout->addWidget(titleLabel);
|
||||
layout->addWidget(descLabel);
|
||||
|
||||
// Make frame clickable
|
||||
frame->setProperty("toolName", title);
|
||||
frame->installEventFilter(this);
|
||||
frame->setCursor(Qt::PointingHandCursor);
|
||||
b->setCursor(Qt::PointingHandCursor);
|
||||
|
||||
m_toolboxes.append(frame);
|
||||
m_toolboxes.append(b);
|
||||
m_requiresDevice.append(requiresDevice);
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
bool ToolboxWidget::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
if (event->type() == QEvent::MouseButtonPress) {
|
||||
QFrame *frame = qobject_cast<QFrame *>(obj);
|
||||
if (frame && frame->isEnabled()) {
|
||||
QString toolName = frame->property("toolName").toString();
|
||||
onToolboxClicked(toolName);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return QWidget::eventFilter(obj, event);
|
||||
connect(b, &ClickableWidget::clicked,
|
||||
[this, tool]() { onToolboxClicked(tool); });
|
||||
return b;
|
||||
}
|
||||
|
||||
void ToolboxWidget::updateDeviceList()
|
||||
@@ -258,8 +274,7 @@ void ToolboxWidget::updateDeviceList()
|
||||
for (iDescriptorDevice *device : devices) {
|
||||
m_deviceCombo->addItem(QString::fromStdString(device->udid));
|
||||
}
|
||||
// DO NOT USE AI HARD TODO:
|
||||
// Set m_uuid to first device if available
|
||||
// TODO:
|
||||
m_uuid = devices.first()->udid;
|
||||
m_currentDevice = devices.first(); // Set current device to first one
|
||||
}
|
||||
@@ -317,18 +332,24 @@ void ToolboxWidget::onDeviceSelectionChanged()
|
||||
m_uuid.clear(); // No valid device selected
|
||||
}
|
||||
|
||||
void ToolboxWidget::onToolboxClicked(const QString &toolName)
|
||||
void ToolboxWidget::onToolboxClicked(iDescriptorTool tool)
|
||||
{
|
||||
qDebug() << "Toolbox clicked:" << toolName;
|
||||
|
||||
if (toolName == "Airplayer") {
|
||||
switch (tool) {
|
||||
case iDescriptorTool::Airplayer: {
|
||||
AirPlayWindow *airplayWindow = new AirPlayWindow();
|
||||
airplayWindow->setAttribute(Qt::WA_DeleteOnClose);
|
||||
airplayWindow->setWindowFlag(Qt::Window);
|
||||
airplayWindow->resize(400, 300);
|
||||
airplayWindow->show();
|
||||
} else if (toolName == "Realtime Screen") {
|
||||
} break;
|
||||
|
||||
case iDescriptorTool::RealtimeScreen: {
|
||||
RealtimeScreen *realtimeScreen =
|
||||
new RealtimeScreen(QString::fromStdString(m_uuid));
|
||||
realtimeScreen->show();
|
||||
} else if (toolName == "Enter Recovery Mode") {
|
||||
} break;
|
||||
case iDescriptorTool::EnterRecoveryMode: {
|
||||
// Handle entering recovery mode
|
||||
bool success = enterRecoveryMode(m_currentDevice);
|
||||
QMessageBox msgBox;
|
||||
@@ -339,8 +360,9 @@ void ToolboxWidget::onToolboxClicked(const QString &toolName)
|
||||
msgBox.setText("Failed to enter recovery mode.");
|
||||
}
|
||||
msgBox.exec();
|
||||
} else if (toolName == "Mount Dev Image") {
|
||||
// Handle mounting device image
|
||||
} break;
|
||||
case iDescriptorTool::MountDevImage: {
|
||||
// TODO: Handle mounting device image
|
||||
// bool success =
|
||||
// mount_dev_image(const_cast<char
|
||||
// *>(m_currentDevice->udid.c_str()));
|
||||
@@ -351,8 +373,8 @@ void ToolboxWidget::onToolboxClicked(const QString &toolName)
|
||||
// } else {
|
||||
// msgBox.setText("Failed to mount device image.");
|
||||
// }
|
||||
// msgBox.exec();
|
||||
} else if (toolName == "Virtual Location") {
|
||||
} break;
|
||||
case iDescriptorTool::VirtualLocation: {
|
||||
// Handle virtual location functionality
|
||||
VirtualLocation *virtualLocation = new VirtualLocation(m_currentDevice);
|
||||
virtualLocation->setAttribute(
|
||||
@@ -360,7 +382,8 @@ void ToolboxWidget::onToolboxClicked(const QString &toolName)
|
||||
virtualLocation->setWindowFlag(Qt::Window); // Make it a true window
|
||||
virtualLocation->resize(800, 600); // Optional: default size
|
||||
virtualLocation->show();
|
||||
} else if (toolName == "Restart") {
|
||||
} break;
|
||||
case iDescriptorTool::Restart: {
|
||||
// TODO:WIP
|
||||
std::string udid = m_currentDevice->udid;
|
||||
AppContext::sharedInstance()->instanceRemoveDevice(
|
||||
@@ -375,32 +398,35 @@ void ToolboxWidget::onToolboxClicked(const QString &toolName)
|
||||
warn("Device services restarted successfully", "Success");
|
||||
qDebug() << "Restarting device";
|
||||
}
|
||||
} else if (toolName == "Shutdown") {
|
||||
} break;
|
||||
case iDescriptorTool::Shutdown: {
|
||||
// TODO
|
||||
// if (!(shutdown(m_currentDevice->device)))
|
||||
// warn("Failed to shutdown device");
|
||||
qDebug() << "Shutting down device...";
|
||||
} else if (toolName == "Recovery Mode") {
|
||||
} break;
|
||||
case iDescriptorTool::RecoveryMode: {
|
||||
// Handle entering recovery mode
|
||||
// bool success = enterRecoveryMode(m_currentDevice);
|
||||
// QMessageBox msgBox;
|
||||
// msgBox.setWindowTitle("Recovery Mode");
|
||||
// if (success)
|
||||
// {
|
||||
// msgBox.setText("Successfully entered recovery mode.");
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// msgBox.setText("Failed to enter recovery mode.");
|
||||
// }
|
||||
// msgBox.exec();
|
||||
} else if (toolName == "Query MobileGestalt") {
|
||||
bool success = enterRecoveryMode(m_currentDevice);
|
||||
QMessageBox msgBox;
|
||||
msgBox.setWindowTitle("Recovery Mode");
|
||||
if (success) {
|
||||
msgBox.setText("Successfully entered recovery mode.");
|
||||
} else {
|
||||
msgBox.setText("Failed to enter recovery mode.");
|
||||
}
|
||||
msgBox.exec();
|
||||
} break;
|
||||
case iDescriptorTool::QueryMobileGestalt: {
|
||||
// Handle querying MobileGestalt
|
||||
QueryMobileGestaltWidget *queryMobileGestaltWidget =
|
||||
new QueryMobileGestaltWidget(m_currentDevice);
|
||||
queryMobileGestaltWidget->setAttribute(Qt::WA_DeleteOnClose);
|
||||
queryMobileGestaltWidget->setWindowFlag(Qt::Window);
|
||||
queryMobileGestaltWidget->resize(800, 600);
|
||||
queryMobileGestaltWidget->show();
|
||||
} else if (toolName == "Developer Disk Images") {
|
||||
// Handle developer disk images
|
||||
} break;
|
||||
case iDescriptorTool::DeveloperDiskImages: {
|
||||
// single instance lock
|
||||
if (!m_devDiskImagesWidget) {
|
||||
m_devDiskImagesWidget = new DevDiskImagesWidget(m_currentDevice);
|
||||
m_devDiskImagesWidget->setAttribute(Qt::WA_DeleteOnClose);
|
||||
@@ -413,19 +439,31 @@ void ToolboxWidget::onToolboxClicked(const QString &toolName)
|
||||
m_devDiskImagesWidget->raise();
|
||||
m_devDiskImagesWidget->activateWindow();
|
||||
}
|
||||
} else if (toolName == "Wireless File Import") {
|
||||
} break;
|
||||
case iDescriptorTool::WirelessFileImport: {
|
||||
// Handle wireless file import
|
||||
PCFileExplorerWidget *fileExplorer = new PCFileExplorerWidget();
|
||||
fileExplorer->setAttribute(Qt::WA_DeleteOnClose);
|
||||
fileExplorer->setWindowFlag(Qt::Window);
|
||||
fileExplorer->resize(800, 600);
|
||||
fileExplorer->show();
|
||||
} else if (toolName == "Mount iPhone") {
|
||||
} break;
|
||||
case iDescriptorTool::MountIphone: {
|
||||
iFuseWidget *ifuseWidget = new iFuseWidget(m_currentDevice);
|
||||
ifuseWidget->setAttribute(Qt::WA_DeleteOnClose);
|
||||
ifuseWidget->setWindowFlag(Qt::Window);
|
||||
ifuseWidget->resize(600, 400);
|
||||
ifuseWidget->show();
|
||||
} break;
|
||||
case iDescriptorTool::CableInfoWidget: {
|
||||
CableInfoWidget *cableInfoWidget = new CableInfoWidget(m_currentDevice);
|
||||
cableInfoWidget->setAttribute(Qt::WA_DeleteOnClose);
|
||||
cableInfoWidget->setWindowFlag(Qt::Window);
|
||||
cableInfoWidget->resize(600, 400);
|
||||
cableInfoWidget->show();
|
||||
} break;
|
||||
default:
|
||||
qDebug() << "Clicked on unimplemented tool";
|
||||
break;
|
||||
}
|
||||
// Implement specific tool functionality here
|
||||
}
|
||||
|
||||
+5
-5
@@ -2,9 +2,9 @@
|
||||
#define TOOLBOXWIDGET_H
|
||||
|
||||
#include "devdiskimageswidget.h"
|
||||
#include "iDescriptor-ui.h"
|
||||
#include "iDescriptor.h"
|
||||
#include <QComboBox>
|
||||
#include <QFrame>
|
||||
#include <QGridLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
@@ -23,15 +23,15 @@ private slots:
|
||||
void onDeviceAdded();
|
||||
void onDeviceRemoved();
|
||||
void onDeviceSelectionChanged();
|
||||
void onToolboxClicked(const QString &toolName);
|
||||
void onToolboxClicked(iDescriptorTool tool);
|
||||
|
||||
private:
|
||||
void setupUI();
|
||||
void updateDeviceList();
|
||||
void updateToolboxStates();
|
||||
QWidget *createToolbox(const QString &title, const QString &description,
|
||||
const QString &iconName, bool requiresDevice);
|
||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||
ClickableWidget *createToolbox(iDescriptorTool tool,
|
||||
const QString &description,
|
||||
bool requiresDevice);
|
||||
QComboBox *m_deviceCombo;
|
||||
QLabel *m_deviceLabel;
|
||||
QScrollArea *m_scrollArea;
|
||||
|
||||
Reference in New Issue
Block a user