Add QML files for Email Parser and Key Generator, and implement main application structure

This commit is contained in:
2026-01-11 02:57:49 +00:00
parent 377ef0cd32
commit 84d020cc6b
6 changed files with 1168 additions and 0 deletions

260
qml/EmailParserTab.qml Normal file
View File

@@ -0,0 +1,260 @@
import QtQuick 6.5
import QtQuick.Controls 6.5
import QtQuick.Layouts 6.5
ScrollView {
id: root
clip: true
contentWidth: availableWidth
ColumnLayout {
width: parent.width
spacing: 15
// Instructions
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: instructionsText.height + 20
color: "#e3f2fd"
radius: 5
Text {
id: instructionsText
anchors.fill: parent
anchors.margins: 10
text: "Parse or Generate Registration Emails:\n\n" +
"• PARSE: Paste a registration email and click 'Parse Email' to extract fields\n" +
"• GENERATE: Fill in the fields below and click 'Generate Email Format' to create formatted text\n" +
"• VALIDATE: Click 'Validate Key' to check if the registration key is correct"
wrapMode: Text.WordWrap
font.pixelSize: 12
}
}
// Email Input Area
GroupBox {
title: "Paste Registration Email Here"
Layout.fillWidth: true
ColumnLayout {
anchors.fill: parent
spacing: 10
ScrollView {
Layout.fillWidth: true
Layout.preferredHeight: 150
TextArea {
id: emailTextArea
placeholderText: "[Registration]\n" +
"First Name: John\n" +
"Last Name: Doe\n" +
"Registered email: john.doe@example.com\n" +
"Serial Number: ABC123\n" +
"Registration Key: XYZ789\n" +
"[End Registration]"
wrapMode: TextArea.Wrap
font.family: "Monospace"
}
}
Button {
text: "Parse Registration Information"
Layout.fillWidth: true
background: Rectangle {
implicitHeight: 40
color: parent.pressed ? "#1976D2" : "#2196F3"
radius: 5
}
contentItem: Text {
text: parent.text
color: "white"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.bold: true
}
onClicked: parseEmail()
}
}
}
// Extracted Information
GroupBox {
title: "Extracted Information"
Layout.fillWidth: true
GridLayout {
anchors.fill: parent
columns: 2
columnSpacing: 10
rowSpacing: 8
Label {
text: "First Name:"
font.bold: true
}
TextField {
id: firstNameOutput
Layout.fillWidth: true
placeholderText: "Enter or parse first name"
}
Label {
text: "Last Name:"
font.bold: true
}
TextField {
id: lastNameOutput
Layout.fillWidth: true
placeholderText: "Enter or parse last name"
}
Label {
text: "Email:"
font.bold: true
}
TextField {
id: emailOutput
Layout.fillWidth: true
placeholderText: "Enter or parse email address"
}
Label {
text: "Serial Number:"
font.bold: true
}
TextField {
id: serialOutput
Layout.fillWidth: true
placeholderText: "Optional serial number"
}
Label {
text: "Registration Key:"
font.bold: true
Layout.alignment: Qt.AlignTop
}
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 60
color: "#ffffff"
border.color: "#ccc"
border.width: 1
radius: 3
ScrollView {
anchors.fill: parent
anchors.margins: 5
TextEdit {
id: keyOutput
width: parent.width
wrapMode: TextEdit.Wrap
font.family: "Courier"
font.pixelSize: 11
font.bold: true
selectByMouse: true
}
}
}
}
}
// Action Buttons
RowLayout {
Layout.fillWidth: true
spacing: 10
Button {
text: "Load Test Data"
Layout.fillWidth: true
background: Rectangle {
implicitHeight: 35
color: parent.pressed ? "#7B1FA2" : "#9C27B0"
radius: 3
}
contentItem: Text {
text: parent.text
color: "white"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.bold: true
font.pixelSize: 13
}
onClicked: loadTestData()
}
Button {
text: "Parse Email"
Layout.fillWidth: true
onClicked: parseEmail()
}
Button {
text: "Generate Email Format"
Layout.fillWidth: true
background: Rectangle {
implicitHeight: 35
color: parent.pressed ? "#45a049" : "#4CAF50"
radius: 3
}
contentItem: Text {
text: parent.text
color: "white"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.bold: true
font.pixelSize: 13
}
onClicked: generateEmail()
}
Button {
text: "Copy Key"
Layout.fillWidth: true
onClicked: copyKey()
}
Button {
text: "Validate Key"
Layout.fillWidth: true
background: Rectangle {
implicitHeight: 35
color: parent.pressed ? "#F57C00" : "#FF9800"
radius: 3
}
contentItem: Text {
text: parent.text
color: "white"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.bold: true
font.pixelSize: 13
}
onClicked: validateKey()
}
}
Item { Layout.fillHeight: true }
}
function loadTestData() {
console.log("Load test data")
}
function parseEmail() {
console.log("Parse email")
}
function generateEmail() {
console.log("Generate email format")
}
function copyKey() {
console.log("Copy key to clipboard")
}
function validateKey() {
console.log("Validate key")
}
}

249
qml/KeyGeneratorTab.qml Normal file
View File

@@ -0,0 +1,249 @@
import QtQuick 6.5
import QtQuick.Controls 6.5
import QtQuick.Layouts 6.5
ScrollView {
id: root
clip: true
property string algorithm: "5-param"
property bool showSecret: true
property bool showMonth: false
property bool showYear: false
property bool showSerial: false
contentWidth: availableWidth
ColumnLayout {
width: parent.width
spacing: 15
// Input Group
GroupBox {
title: "Input Parameters"
Layout.fillWidth: true
GridLayout {
anchors.fill: parent
columns: 2
columnSpacing: 10
rowSpacing: 8
Label {
text: "First Name:"
font.bold: true
}
TextField {
id: firstNameField
Layout.fillWidth: true
placeholderText: "Enter first name"
}
Label {
text: "Last Name:"
font.bold: true
}
TextField {
id: lastNameField
Layout.fillWidth: true
placeholderText: "Enter last name"
}
Label {
text: "Product Name:"
font.bold: true
}
ComboBox {
id: productField
Layout.fillWidth: true
editable: true
model: ["MegaLogViewer", "TunerStudio", "DataLogger"]
}
Label {
text: "Secret Key:"
font.bold: true
visible: showSecret
}
TextField {
id: secretField
Layout.fillWidth: true
placeholderText: "Enter secret key"
visible: showSecret
}
Label {
text: "Email:"
font.bold: true
}
TextField {
id: emailField
Layout.fillWidth: true
placeholderText: "Enter email address"
}
Label {
text: "Month:"
font.bold: true
visible: showMonth
}
TextField {
id: monthField
Layout.fillWidth: true
text: "01"
placeholderText: "MM"
visible: showMonth
}
Label {
text: "Year:"
font.bold: true
visible: showYear
}
TextField {
id: yearField
Layout.fillWidth: true
text: "2015"
placeholderText: "YYYY"
visible: showYear
}
Label {
text: "Serial Number:"
font.bold: true
visible: showSerial
}
TextField {
id: serialField
Layout.fillWidth: true
placeholderText: "Enter serial number"
visible: showSerial
}
}
}
// Buttons
RowLayout {
Layout.fillWidth: true
spacing: 10
Button {
text: "Load Test Data"
Layout.fillWidth: true
background: Rectangle {
implicitHeight: 40
color: parent.pressed ? "#1976D2" : "#2196F3"
radius: 5
}
contentItem: Text {
text: parent.text
color: "white"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.bold: true
}
onClicked: loadTestData()
}
Button {
text: "Generate Key"
Layout.fillWidth: true
background: Rectangle {
implicitHeight: 40
color: parent.pressed ? "#45a049" : "#4CAF50"
radius: 5
}
contentItem: Text {
text: parent.text
color: "white"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.bold: true
}
onClicked: generateKey()
}
Button {
text: "Validate Key"
Layout.fillWidth: true
background: Rectangle {
implicitHeight: 40
color: parent.pressed ? "#F57C00" : "#FF9800"
radius: 5
}
contentItem: Text {
text: parent.text
color: "white"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.bold: true
}
onClicked: validateKey()
}
}
// Output Group
GroupBox {
title: "Generated Registration Key"
Layout.fillWidth: true
ColumnLayout {
anchors.fill: parent
spacing: 10
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 80
color: "#e8f5e9"
border.color: "#4CAF50"
border.width: 2
radius: 5
ScrollView {
anchors.fill: parent
anchors.margins: 5
TextEdit {
id: outputField
width: parent.width
wrapMode: TextEdit.Wrap
readOnly: true
font.family: "Courier"
font.pixelSize: 14
font.bold: true
selectByMouse: true
}
}
}
Button {
text: "Copy to Clipboard"
Layout.fillWidth: true
onClicked: copyToClipboard()
}
}
}
Item { Layout.fillHeight: true }
}
function loadTestData() {
// This would call Python backend
console.log("Load test data for", algorithm)
}
function generateKey() {
// This would call Python backend
console.log("Generate key for", algorithm)
}
function validateKey() {
// This would call Python backend
console.log("Validate key for", algorithm)
}
function copyToClipboard() {
// Copy output to clipboard
console.log("Copy to clipboard")
}
}

99
qml/Main.qml Normal file
View File

@@ -0,0 +1,99 @@
import QtQuick 6.5
import QtQuick.Controls 6.5
import QtQuick.Layouts 6.5
import QtQuick.Window 6.5
ApplicationWindow {
id: mainWindow
visible: true
width: 600
height: 700
minimumWidth: 500
minimumHeight: 600
title: "Registration Key Generator"
// Color scheme
readonly property color primaryColor: "#4CAF50"
readonly property color accentColor: "#2196F3"
readonly property color warningColor: "#FF9800"
readonly property color errorColor: "#f44336"
readonly property color backgroundColor: "#f5f5f5"
readonly property color cardColor: "#ffffff"
TabBar {
id: tabBar
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
TabButton {
text: "4-Parameter"
font.pixelSize: 13
}
TabButton {
text: "5-Parameter"
font.pixelSize: 13
}
TabButton {
text: "7-Parameter"
font.pixelSize: 13
}
TabButton {
text: "8-Parameter"
font.pixelSize: 13
}
TabButton {
text: "Email Parser"
font.pixelSize: 13
}
}
StackLayout {
anchors.top: tabBar.bottom
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: 10
currentIndex: tabBar.currentIndex
// 4-Parameter Tab
KeyGeneratorTab {
algorithm: "4-param"
showSecret: false
showMonth: false
showYear: false
showSerial: false
}
// 5-Parameter Tab
KeyGeneratorTab {
algorithm: "5-param"
showSecret: true
showMonth: false
showYear: false
showSerial: false
}
// 7-Parameter Tab
KeyGeneratorTab {
algorithm: "7-param"
showSecret: true
showMonth: true
showYear: true
showSerial: false
}
// 8-Parameter Tab
KeyGeneratorTab {
algorithm: "8-param"
showSecret: true
showMonth: true
showYear: true
showSerial: true
}
// Email Parser Tab
EmailParserTab {
}
}
}

180
qml/README.md Normal file
View File

@@ -0,0 +1,180 @@
# QML Registration GUI
Modern QML-based user interface for the Registration Key Generator, based on the original Java Swing GUI (`com/efiAnalytics/ui/dS.java`).
## Features
### QML Implementation
- **Main.qml** - Main application window with tab navigation
- **KeyGeneratorTab.qml** - Reusable tab component for key generation (4/5/7/8-parameter variants)
- **EmailParserTab.qml** - Email parsing and generation functionality
- **RegistrationDialog.qml** - Registration dialog matching Java `dS.java` design
- **main.py** - Python backend connecting QML to registration algorithms
### UI Components
#### Main Window
- Tab-based navigation (matches PyQt6 GUI structure)
- 5 tabs: 4-Parameter, 5-Parameter, 7-Parameter, 8-Parameter, Email Parser
- Modern Material Design color scheme
- Responsive layout
#### Key Generator Tabs
Based on Java Swing input panels from `dS.java`:
- Input fields for first name, last name, product, email
- Conditional fields (secret, month, year, serial) based on algorithm
- "Load Test Data" button (blue) - auto-populate with valid test data
- "Generate Key" button (green) - create registration key
- "Validate Key" button (orange) - verify key correctness
- Output area with monospace font
- Copy to clipboard functionality
#### Email Parser Tab
Based on Java "Paste Email" functionality from `dS.java`:
- Text area for pasting registration emails
- Parse button to extract fields from `[Registration]...[End Registration]` format
- Editable extracted fields (first name, last name, email, serial, key)
- "Load Test Data" button (purple) - generates complete valid registration
- "Generate Email Format" button (green) - creates formatted email text
- Validation support
#### Registration Dialog
Matches Java `dS.java` dialog structure:
- Radio buttons to switch between "Inputs" and "Paste Email" views
- CardLayout equivalent using QML StackLayout
- Edition selector (ComboBox)
- Registration information fields
- Email paste and parse functionality
- OK/Cancel standard dialog buttons
## Architecture
### QML Frontend
- Declarative UI using QtQuick 6.5
- Material Design styling
- Signal/slot connections to Python backend
- Responsive layouts with GridLayout, RowLayout, ColumnLayout
### Python Backend (main.py)
- `RegistrationBackend` class exposes methods to QML
- Uses `@pyqtSlot` decorators for QML-callable methods
- Imports from `registration_gui.py` for algorithm implementations
- Signal emissions for async operations
### Backend Methods
- `generateKey4Param()` - 4-parameter algorithm
- `generateKey5Param()` - 5-parameter algorithm
- `generateKey7Param()` - 7-parameter algorithm
- `generateKey8Param()` - 8-parameter algorithm
- `loadTestData()` - Generate dummy test data
- `parseEmail()` - Extract fields from email text
- `generateEmailFormat()` - Create formatted registration email
## Running the QML GUI
```bash
# Install Qt6 for Python
pip install PyQt6
# Run the QML application
cd qml
python3 main.py
```
## Comparison: Java Swing vs QML
### Java Swing (Original)
```java
// dS.java - Registration Dialog
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(0, 1, 3, 3));
ea firstNameField = new ea(this, "Registered First Name:", k.b());
panel.add(firstNameField);
```
### QML (Modern)
```qml
// RegistrationDialog.qml
GridLayout {
columns: 2
Label { text: "Registered First Name:" }
TextField {
id: firstNameField
Layout.fillWidth: true
}
}
```
## Advantages of QML
1. **Declarative Syntax** - Easier to read and maintain than imperative Java Swing
2. **Modern Look** - Material Design colors and styling
3. **Responsive** - Automatic layout adjustment
4. **Animation Support** - Built-in property animations
5. **Hardware Acceleration** - Qt Quick Scene Graph for smooth rendering
6. **Cross-Platform** - Same QML runs on Windows, macOS, Linux, mobile
7. **Separation of Concerns** - UI in QML, logic in Python
8. **Hot Reload** - Can reload QML without restarting (in development)
## Java GUI Elements Mapped to QML
| Java Swing Component | QML Component | Location |
|---------------------|---------------|----------|
| `JDialog` | `Dialog` | RegistrationDialog.qml |
| `JPanel` | `Rectangle` + Layout | All files |
| `JTextField` | `TextField` | KeyGeneratorTab.qml, etc. |
| `JTextArea` / `JTextPane` | `TextArea` / `TextEdit` | EmailParserTab.qml |
| `JButton` | `Button` | All files |
| `JRadioButton` | `RadioButton` | RegistrationDialog.qml |
| `ButtonGroup` | `ButtonGroup` | RegistrationDialog.qml |
| `JComboBox` | `ComboBox` | KeyGeneratorTab.qml |
| `GridLayout` | `GridLayout` | KeyGeneratorTab.qml |
| `BorderLayout` | `ColumnLayout` + anchors | Main.qml |
| `CardLayout` | `StackLayout` | RegistrationDialog.qml |
| `JScrollPane` | `ScrollView` | EmailParserTab.qml |
| `GroupBox` (titled border) | `GroupBox` | All tabs |
## File Structure
```
qml/
├── Main.qml # Main application window
├── KeyGeneratorTab.qml # Reusable key generation tab
├── EmailParserTab.qml # Email parsing/generation tab
├── RegistrationDialog.qml # Registration dialog (matches dS.java)
├── main.py # Python backend + QML loader
└── README.md # This file
```
## Next Steps
To fully connect the QML UI to the Python backend:
1. **Implement Backend Calls** - Connect QML button clicks to Python slots
2. **Add Clipboard Support** - Use `QClipboard` for copy/paste
3. **Error Handling** - Display validation errors in QML dialogs
4. **Styling** - Add custom Material Design theme
5. **Animations** - Add smooth transitions between tabs
6. **Testing** - Create QML test cases
## Color Scheme
```qml
primaryColor: "#4CAF50" // Green - Generate buttons
accentColor: "#2196F3" // Blue - Load Test Data
warningColor: "#FF9800" // Orange - Validate buttons
errorColor: "#f44336" // Red - Errors
backgroundColor: "#f5f5f5" // Light gray
cardColor: "#ffffff" // White
```
## Dependencies
- Python 3.6+
- PyQt6 6.5.0+
- Qt 6.5+ (included with PyQt6)
- registration_gui.py (from parent directory)
## License
Same as parent project - for educational and testing purposes.

205
qml/RegistrationDialog.qml Normal file
View File

@@ -0,0 +1,205 @@
// Registration Dialog based on Java dS.java
import QtQuick 6.5
import QtQuick.Controls 6.5
import QtQuick.Layouts 6.5
import QtQuick.Window 6.5
Dialog {
id: registrationDialog
title: "Enter Registration Information"
width: 500
height: 600
modal: true
standardButtons: Dialog.Ok | Dialog.Cancel
property string productName: "MegaLogViewer"
property var editions: ["Standard", "Pro", "Enterprise"]
ColumnLayout {
anchors.fill: parent
spacing: 10
// Radio buttons for input method
ButtonGroup {
id: inputMethodGroup
buttons: [inputsRadio, pasteEmailRadio]
}
RowLayout {
Layout.fillWidth: true
spacing: 20
RadioButton {
id: inputsRadio
text: "Inputs"
checked: true
onClicked: stackLayout.currentIndex = 0
}
RadioButton {
id: pasteEmailRadio
text: "Paste Email"
onClicked: stackLayout.currentIndex = 1
}
}
Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
border.color: "#ccc"
border.width: 1
radius: 5
StackLayout {
id: stackLayout
anchors.fill: parent
anchors.margins: 10
currentIndex: 0
// Inputs View
ScrollView {
Layout.fillWidth: true
Layout.fillHeight: true
ColumnLayout {
width: parent.width
spacing: 10
// Edition Selector
GroupBox {
title: "Register " + productName + " (Select Edition)"
Layout.fillWidth: true
ComboBox {
id: editionCombo
anchors.fill: parent
model: editions
}
}
// Registration Information
GroupBox {
title: "Registration Information"
Layout.fillWidth: true
GridLayout {
anchors.fill: parent
columns: 2
columnSpacing: 10
rowSpacing: 8
Label { text: "Registered First Name:" }
TextField {
id: firstNameField
Layout.fillWidth: true
}
Label { text: "Registered Last Name:" }
TextField {
id: lastNameField
Layout.fillWidth: true
}
Label { text: "Registered eMail Address:" }
TextField {
id: emailField
Layout.fillWidth: true
}
Label { text: "Registration Key:" }
TextField {
id: registrationKeyField
Layout.fillWidth: true
font.family: "Courier"
}
Label { text: "Serial Number:" }
TextField {
id: serialField
Layout.fillWidth: true
}
}
}
}
}
// Paste Email View
ColumnLayout {
Layout.fillWidth: true
Layout.fillHeight: true
spacing: 10
Button {
text: "Paste"
Layout.alignment: Qt.AlignHCenter
onClicked: pasteFromClipboard()
}
ScrollView {
Layout.fillWidth: true
Layout.fillHeight: true
TextArea {
id: pasteTextArea
placeholderText: "Paste registration email here..."
wrapMode: TextArea.Wrap
font.family: "Monospace"
onTextChanged: parseEmailText()
}
}
}
}
}
}
onAccepted: {
// Validate and process registration
console.log("Registration submitted")
console.log("First Name:", firstNameField.text)
console.log("Last Name:", lastNameField.text)
console.log("Email:", emailField.text)
console.log("Key:", registrationKeyField.text)
}
function pasteFromClipboard() {
// Get text from clipboard
pasteTextArea.text = ""; // Would paste from actual clipboard
}
function parseEmailText() {
var text = pasteTextArea.text
var lines = text.split('\n')
var inRegistration = false
for (var i = 0; i < lines.length; i++) {
var line = lines[i].trim()
if (line.includes('[Registration]')) {
inRegistration = true
continue
}
if (line.includes('[End Registration]')) {
break
}
if (inRegistration) {
if (line.startsWith('First Name')) {
firstNameField.text = line.substring(line.indexOf(':') + 1).trim()
}
else if (line.startsWith('Last Name')) {
lastNameField.text = line.substring(line.indexOf(':') + 1).trim()
}
else if (line.startsWith('Registered email')) {
emailField.text = line.substring(line.indexOf(':') + 1).trim()
}
else if (line.includes('Serial Number')) {
serialField.text = line.substring(line.indexOf(':') + 1).trim()
}
else if (line.startsWith('Registration Key')) {
registrationKeyField.text = line.substring(line.indexOf(':') + 1).trim()
}
}
}
}
}

175
qml/main.py Normal file
View File

@@ -0,0 +1,175 @@
#!/usr/bin/env python3
"""
QML-based Registration Key Generator
Uses Qt6 QML for the UI with Python backend
"""
import sys
import os
from pathlib import Path
# Add parent directory to path for imports
sys.path.insert(0, str(Path(__file__).parent.parent))
from PyQt6.QtCore import QObject, pyqtSlot, pyqtSignal, pyqtProperty
from PyQt6.QtGui import QGuiApplication
from PyQt6.QtQml import QQmlApplicationEngine
from registration_gui import RegistrationKeyGenerator, DummyDataGenerator
class RegistrationBackend(QObject):
"""Backend for QML UI"""
keyGenerated = pyqtSignal(str)
errorOccurred = pyqtSignal(str)
testDataLoaded = pyqtSignal(str, str, str, str, str, str)
def __init__(self):
super().__init__()
self.generator = RegistrationKeyGenerator()
@pyqtSlot(str, str, str, str, result=str)
def generateKey4Param(self, firstName, lastName, product, email):
"""Generate 4-parameter key"""
try:
key = RegistrationKeyGenerator.generate_key_basic(
firstName, lastName, product, email
)
return key if key else ""
except Exception as e:
self.errorOccurred.emit(str(e))
return ""
@pyqtSlot(str, str, str, str, str, result=str)
def generateKey5Param(self, firstName, lastName, product, secret, email):
"""Generate 5-parameter key"""
try:
key = RegistrationKeyGenerator.generate_key_5param(
firstName, lastName, product, secret, email
)
return key if key else ""
except Exception as e:
self.errorOccurred.emit(str(e))
return ""
@pyqtSlot(str, str, str, str, str, str, str, result=str)
def generateKey7Param(self, firstName, lastName, product, secret, email, month, year):
"""Generate 7-parameter key"""
try:
key = RegistrationKeyGenerator.generate_key_7param(
firstName, lastName, product, secret, email, month, year
)
return key if key else ""
except Exception as e:
self.errorOccurred.emit(str(e))
return ""
@pyqtSlot(str, str, str, str, str, str, str, str, result=str)
def generateKey8Param(self, firstName, lastName, product, secret, email, month, year, serial):
"""Generate 8-parameter key"""
try:
key = RegistrationKeyGenerator.generate_key_8param(
firstName, lastName, product, secret, email, month, year, serial
)
return key if key else ""
except Exception as e:
self.errorOccurred.emit(str(e))
return ""
@pyqtSlot(result=str)
def loadTestData(self):
"""Load test data and return as JSON string"""
data = DummyDataGenerator.generate()
# Emit signal with test data
self.testDataLoaded.emit(
data['first_name'],
data['last_name'],
data['email'],
data['product'],
data['secret'],
data['serial']
)
return f"{data['first_name']}|{data['last_name']}|{data['email']}|{data['product']}|{data['secret']}|{data['serial']}"
@pyqtSlot(str, result=str)
def parseEmail(self, emailText):
"""Parse email text and return extracted fields"""
lines = emailText.split('\n')
in_registration = False
result = {
'firstName': '',
'lastName': '',
'email': '',
'serial': '',
'key': ''
}
for line in lines:
line = line.strip()
if '[Registration]' in line:
in_registration = True
continue
if '[End Registration]' in line:
break
if in_registration:
if line.startswith('First Name') and ':' in line:
result['firstName'] = line.split(':', 1)[1].strip()
elif line.startswith('Last Name') and ':' in line:
result['lastName'] = line.split(':', 1)[1].strip()
elif 'email' in line.lower() and ':' in line:
result['email'] = line.split(':', 1)[1].strip()
elif 'Serial Number' in line and ':' in line:
result['serial'] = line.split(':', 1)[1].strip()
elif 'Registration Key' in line and ':' in line:
result['key'] = line.split(':', 1)[1].strip()
# Return as delimited string
return f"{result['firstName']}|{result['lastName']}|{result['email']}|{result['serial']}|{result['key']}"
@pyqtSlot(str, str, str, str, str, result=str)
def generateEmailFormat(self, firstName, lastName, email, serial, key):
"""Generate registration email format"""
email_format = "[Registration]\n"
email_format += f"First Name: {firstName}\n"
email_format += f"Last Name: {lastName}\n"
email_format += f"Registered email: {email}\n"
if serial:
email_format += f"Serial Number: {serial}\n"
email_format += f"Registration Key: {key}\n"
email_format += "[End Registration]"
return email_format
def main():
app = QGuiApplication(sys.argv)
app.setApplicationName("Registration Key Generator")
app.setOrganizationName("EFI Analytics")
engine = QQmlApplicationEngine()
# Create backend and register it
backend = RegistrationBackend()
engine.rootContext().setContextProperty("backend", backend)
# Load QML
qml_file = Path(__file__).parent / "Main.qml"
engine.load(str(qml_file))
if not engine.rootObjects():
return -1
return app.exec()
if __name__ == "__main__":
sys.exit(main())