|
22 | 22 | QPushButton, QLabel, QTextEdit, QScrollArea, QFrame, QSplitter, QGroupBox,
|
23 | 23 | QComboBox, QCheckBox, QSpinBox, QProgressBar, QStatusBar, QFileDialog,
|
24 | 24 | QMessageBox, QDialog, QRadioButton, QButtonGroup, QDialogButtonBox,
|
25 |
| - QTabWidget, QSlider, QLineEdit |
| 25 | + QTabWidget, QSlider, QLineEdit, QInputDialog |
26 | 26 | )
|
27 | 27 | from PySide6.QtCore import (
|
28 |
| - Qt, QThread, Signal, QTimer, QSize, QRect, QPoint, QMutex, QMutexLocker |
| 28 | + Qt, QThread, Signal, QTimer, QSize, QRect, QPoint, QMutex, QMutexLocker, QUrl |
29 | 29 | )
|
30 | 30 | from PySide6.QtGui import (
|
31 | 31 | QPixmap, QImage, QPainter, QPen, QBrush, QColor, QFont, QAction,
|
32 |
| - QDragEnterEvent, QDropEvent, QClipboard, QIcon |
| 32 | + QDragEnterEvent, QDropEvent, QClipboard, QIcon, QDesktopServices |
33 | 33 | )
|
34 | 34 | from PySide6.QtMultimedia import QCamera, QMediaDevices
|
35 | 35 | from PySide6.QtMultimediaWidgets import QVideoWidget
|
@@ -1098,6 +1098,112 @@ def get_selected_format(self):
|
1098 | 1098 | """Get the selected format index."""
|
1099 | 1099 | return self.selected_format
|
1100 | 1100 |
|
| 1101 | +class LicenseDialog(QDialog): |
| 1102 | + """Custom dialog for license key entry with trial license option.""" |
| 1103 | + |
| 1104 | + def __init__(self, current_license_key, parent=None): |
| 1105 | + super().__init__(parent) |
| 1106 | + self.setWindowTitle("License Management") |
| 1107 | + self.setFixedSize(500, 300) |
| 1108 | + self.license_key = "" |
| 1109 | + self.result_type = None # 'license', 'trial', or None |
| 1110 | + |
| 1111 | + layout = QVBoxLayout() |
| 1112 | + |
| 1113 | + # Title |
| 1114 | + title = QLabel("🔑 Dynamsoft License Management") |
| 1115 | + title.setFont(QFont("Arial", 14, QFont.Weight.Bold)) |
| 1116 | + title.setAlignment(Qt.AlignmentFlag.AlignCenter) |
| 1117 | + layout.addWidget(title) |
| 1118 | + |
| 1119 | + # Current license info |
| 1120 | + current_key_display = current_license_key[:20] + "..." if len(current_license_key) > 20 else current_license_key |
| 1121 | + current_info = QLabel(f"Current license: {current_key_display}") |
| 1122 | + current_info.setStyleSheet("color: gray; font-size: 10px; padding: 10px;") |
| 1123 | + layout.addWidget(current_info) |
| 1124 | + |
| 1125 | + # License key input |
| 1126 | + input_group = QGroupBox("Enter New License Key") |
| 1127 | + input_layout = QVBoxLayout(input_group) |
| 1128 | + |
| 1129 | + self.license_input = QLineEdit() |
| 1130 | + self.license_input.setPlaceholderText("Paste your Dynamsoft license key here...") |
| 1131 | + input_layout.addWidget(self.license_input) |
| 1132 | + |
| 1133 | + layout.addWidget(input_group) |
| 1134 | + |
| 1135 | + # Trial license section |
| 1136 | + trial_group = QGroupBox("Need a License?") |
| 1137 | + trial_layout = QVBoxLayout(trial_group) |
| 1138 | + |
| 1139 | + trial_info = QLabel("Get a 30-day free trial license from Dynamsoft:") |
| 1140 | + trial_layout.addWidget(trial_info) |
| 1141 | + |
| 1142 | + self.trial_button = QPushButton("🌐 Get 30-Day Trial License") |
| 1143 | + self.trial_button.setStyleSheet(""" |
| 1144 | + QPushButton { |
| 1145 | + background-color: #007acc; |
| 1146 | + color: white; |
| 1147 | + padding: 10px; |
| 1148 | + border: none; |
| 1149 | + border-radius: 5px; |
| 1150 | + font-weight: bold; |
| 1151 | + } |
| 1152 | + QPushButton:hover { |
| 1153 | + background-color: #005a9e; |
| 1154 | + } |
| 1155 | + """) |
| 1156 | + self.trial_button.clicked.connect(self.open_trial_page) |
| 1157 | + trial_layout.addWidget(self.trial_button) |
| 1158 | + |
| 1159 | + layout.addWidget(trial_group) |
| 1160 | + |
| 1161 | + # Buttons |
| 1162 | + button_layout = QHBoxLayout() |
| 1163 | + |
| 1164 | + self.apply_button = QPushButton("Apply License") |
| 1165 | + self.apply_button.setDefault(True) |
| 1166 | + self.apply_button.clicked.connect(self.apply_license) |
| 1167 | + |
| 1168 | + cancel_button = QPushButton("Cancel") |
| 1169 | + cancel_button.clicked.connect(self.reject) |
| 1170 | + |
| 1171 | + button_layout.addWidget(cancel_button) |
| 1172 | + button_layout.addWidget(self.apply_button) |
| 1173 | + |
| 1174 | + layout.addLayout(button_layout) |
| 1175 | + self.setLayout(layout) |
| 1176 | + |
| 1177 | + def open_trial_page(self): |
| 1178 | + """Open the trial license page in the default browser.""" |
| 1179 | + trial_url = "https://www.dynamsoft.com/customer/license/trialLicense/?product=dcv&package=cross-platform" |
| 1180 | + QDesktopServices.openUrl(QUrl(trial_url)) |
| 1181 | + |
| 1182 | + # Show info message |
| 1183 | + QMessageBox.information( |
| 1184 | + self, |
| 1185 | + "Trial License", |
| 1186 | + "🌐 The trial license page has been opened in your browser.\n\n" |
| 1187 | + "Steps to get your trial license:\n" |
| 1188 | + "1. Fill out the form on the opened page\n" |
| 1189 | + "2. Submit to receive your license key via email\n" |
| 1190 | + "3. Copy the license key and paste it here\n" |
| 1191 | + "4. Click 'Apply License' to activate" |
| 1192 | + ) |
| 1193 | + |
| 1194 | + def apply_license(self): |
| 1195 | + """Apply the entered license key.""" |
| 1196 | + self.license_key = self.license_input.text().strip() |
| 1197 | + if self.license_key: |
| 1198 | + self.result_type = 'license' |
| 1199 | + self.accept() |
| 1200 | + else: |
| 1201 | + QMessageBox.warning(self, "Missing License", "Please enter a license key.") |
| 1202 | + |
| 1203 | + def get_license_key(self): |
| 1204 | + """Get the entered license key.""" |
| 1205 | + return self.license_key |
| 1206 | + |
1101 | 1207 | class BarcodeReaderMainWindow(QMainWindow):
|
1102 | 1208 | """Main window for the PySide6 barcode reader application with camera support."""
|
1103 | 1209 |
|
@@ -1600,6 +1706,13 @@ def setup_menu_bar(self):
|
1600 | 1706 | exit_action.triggered.connect(self.close)
|
1601 | 1707 | file_menu.addAction(exit_action)
|
1602 | 1708 |
|
| 1709 | + # Settings menu |
| 1710 | + settings_menu = menubar.addMenu("Settings") |
| 1711 | + |
| 1712 | + license_action = QAction("Enter License Key...", self) |
| 1713 | + license_action.triggered.connect(self.enter_license_key) |
| 1714 | + settings_menu.addAction(license_action) |
| 1715 | + |
1603 | 1716 | # View menu
|
1604 | 1717 | view_menu = menubar.addMenu("View")
|
1605 | 1718 |
|
@@ -2923,6 +3036,78 @@ def show_about(self):
|
2923 | 3036 | "• Export capabilities (TXT, CSV, JSON)\n"
|
2924 | 3037 | "• Professional user interface\n\n"
|
2925 | 3038 | "Supports both file-based and live camera scanning.")
|
| 3039 | + |
| 3040 | + def enter_license_key(self): |
| 3041 | + """Show dialog to enter a new license key.""" |
| 3042 | + global LICENSE_KEY, _LICENSE_INITIALIZED |
| 3043 | + |
| 3044 | + # Show custom license dialog |
| 3045 | + dialog = LicenseDialog(LICENSE_KEY, self) |
| 3046 | + if dialog.exec() == QDialog.DialogCode.Accepted: |
| 3047 | + license_key = dialog.get_license_key() |
| 3048 | + |
| 3049 | + if license_key: |
| 3050 | + # Show confirmation dialog |
| 3051 | + reply = QMessageBox.question( |
| 3052 | + self, |
| 3053 | + "Update License", |
| 3054 | + f"Update license key to:\n{license_key[:20]}...\n\nThe license will be tested and applied.\n\nContinue?", |
| 3055 | + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, |
| 3056 | + QMessageBox.StandardButton.No |
| 3057 | + ) |
| 3058 | + |
| 3059 | + if reply == QMessageBox.StandardButton.Yes: |
| 3060 | + try: |
| 3061 | + # Test the new license |
| 3062 | + test_error_code, test_error_message = LicenseManager.init_license(license_key) |
| 3063 | + |
| 3064 | + if test_error_code == EnumErrorCode.EC_OK or test_error_code == EnumErrorCode.EC_LICENSE_CACHE_USED: |
| 3065 | + # License is valid, update the global LICENSE_KEY |
| 3066 | + LICENSE_KEY = license_key |
| 3067 | + |
| 3068 | + # Reinitialize the license system |
| 3069 | + _LICENSE_INITIALIZED = False |
| 3070 | + |
| 3071 | + if initialize_license_once(): |
| 3072 | + # Reinitialize the CVR instance |
| 3073 | + if self.cvr_instance: |
| 3074 | + self.cvr_instance = None |
| 3075 | + |
| 3076 | + self.cvr_instance = CaptureVisionRouter() |
| 3077 | + intermediate_result_manager = self.cvr_instance.get_intermediate_result_manager() |
| 3078 | + self.custom_receiver = MyIntermediateResultReceiver(intermediate_result_manager) |
| 3079 | + intermediate_result_manager.add_result_receiver(self.custom_receiver) |
| 3080 | + |
| 3081 | + # Update camera widget if it exists |
| 3082 | + if hasattr(self, 'camera_widget'): |
| 3083 | + self.camera_widget.initialize_dynamsoft_camera(self.cvr_instance) |
| 3084 | + |
| 3085 | + QMessageBox.information( |
| 3086 | + self, |
| 3087 | + "License Updated", |
| 3088 | + "✅ License key updated successfully!\n\nThe new license is now active." |
| 3089 | + ) |
| 3090 | + |
| 3091 | + self.log_message("✅ License key updated successfully") |
| 3092 | + else: |
| 3093 | + QMessageBox.critical( |
| 3094 | + self, |
| 3095 | + "License Error", |
| 3096 | + "❌ Failed to reinitialize with new license key.\n\nPlease restart the application." |
| 3097 | + ) |
| 3098 | + else: |
| 3099 | + QMessageBox.critical( |
| 3100 | + self, |
| 3101 | + "Invalid License", |
| 3102 | + f"❌ License validation failed:\n\nError Code: {test_error_code}\nError Message: {test_error_message}\n\nPlease check your license key and try again." |
| 3103 | + ) |
| 3104 | + |
| 3105 | + except Exception as e: |
| 3106 | + QMessageBox.critical( |
| 3107 | + self, |
| 3108 | + "License Error", |
| 3109 | + f"❌ Error updating license:\n\n{str(e)}\n\nPlease try again or restart the application." |
| 3110 | + ) |
2926 | 3111 |
|
2927 | 3112 | def main():
|
2928 | 3113 | """Main application entry point."""
|
|
0 commit comments