Feat: Add Status Bar with Progress Bar for Load on Save operations
This commit is contained in:
@@ -1,10 +1,15 @@
|
|||||||
import os
|
import os
|
||||||
from typing import List
|
from typing import List, Callable, Optional
|
||||||
from .models import Packet, Page, TeletextService
|
from .models import Packet, Page, TeletextService
|
||||||
|
|
||||||
def load_t42(file_path: str) -> TeletextService:
|
def load_t42(file_path: str, progress_callback: Optional[Callable[[int, int], None]] = None) -> TeletextService:
|
||||||
service = TeletextService()
|
service = TeletextService()
|
||||||
|
|
||||||
|
total_bytes = os.path.getsize(file_path)
|
||||||
|
# Each packet is 42 bytes
|
||||||
|
total_packets = total_bytes // 42
|
||||||
|
processed_packets = 0
|
||||||
|
|
||||||
with open(file_path, 'rb') as f:
|
with open(file_path, 'rb') as f:
|
||||||
while True:
|
while True:
|
||||||
chunk = f.read(42)
|
chunk = f.read(42)
|
||||||
@@ -14,6 +19,10 @@ def load_t42(file_path: str) -> TeletextService:
|
|||||||
# Should not happen in a valid T42 stream, or we just ignore incomplete tail
|
# Should not happen in a valid T42 stream, or we just ignore incomplete tail
|
||||||
break
|
break
|
||||||
|
|
||||||
|
processed_packets += 1
|
||||||
|
if progress_callback and processed_packets % 100 == 0:
|
||||||
|
progress_callback(processed_packets, total_packets)
|
||||||
|
|
||||||
packet = Packet(chunk)
|
packet = Packet(chunk)
|
||||||
service.all_packets.append(packet)
|
service.all_packets.append(packet)
|
||||||
|
|
||||||
@@ -114,9 +123,16 @@ def decode_packet_header(b1, b2):
|
|||||||
row = (d2 << 1) | ((d1 >> 3) & 1)
|
row = (d2 << 1) | ((d1 >> 3) & 1)
|
||||||
return mag, row
|
return mag, row
|
||||||
|
|
||||||
def save_t42(file_path: str, service: TeletextService):
|
def save_t42(file_path: str, service: TeletextService, progress_callback: Optional[Callable[[int, int], None]] = None):
|
||||||
|
total_packets = len(service.all_packets)
|
||||||
|
processed = 0
|
||||||
|
|
||||||
with open(file_path, 'wb') as f:
|
with open(file_path, 'wb') as f:
|
||||||
for packet in service.all_packets:
|
for packet in service.all_packets:
|
||||||
|
processed += 1
|
||||||
|
if progress_callback and processed % 100 == 0:
|
||||||
|
progress_callback(processed, total_packets)
|
||||||
|
|
||||||
# Check if we can reuse the original header (preserving parity/integrity)
|
# Check if we can reuse the original header (preserving parity/integrity)
|
||||||
use_original_header = False
|
use_original_header = False
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
|
|
||||||
from PyQt6.QtWidgets import (QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
|
from PyQt6.QtWidgets import (
|
||||||
QListWidget, QListWidgetItem, QComboBox, QLabel, QLineEdit, QPushButton, QFileDialog, QMenuBar, QMenu, QMessageBox)
|
QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
|
||||||
|
QListWidget, QListWidgetItem, QComboBox, QLabel, QLineEdit, QPushButton,
|
||||||
|
QFileDialog, QMenuBar, QMenu, QMessageBox, QStatusBar, QProgressBar, QApplication
|
||||||
|
)
|
||||||
|
|
||||||
# ... (imports remain)
|
# ... (imports remain)
|
||||||
|
|
||||||
@@ -10,6 +13,8 @@ from PyQt6.QtCore import Qt
|
|||||||
|
|
||||||
from .io import load_t42, save_t42
|
from .io import load_t42, save_t42
|
||||||
from .renderer import TeletextCanvas
|
from .renderer import TeletextCanvas
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
from .models import TeletextService, Page, Packet
|
from .models import TeletextService, Page, Packet
|
||||||
|
|
||||||
class MainWindow(QMainWindow):
|
class MainWindow(QMainWindow):
|
||||||
@@ -170,6 +175,7 @@ class MainWindow(QMainWindow):
|
|||||||
# Reset everything
|
# Reset everything
|
||||||
self.service = TeletextService()
|
self.service = TeletextService()
|
||||||
self.current_page = None
|
self.current_page = None
|
||||||
|
self.current_file_path = None
|
||||||
self.populate_list()
|
self.populate_list()
|
||||||
self.subpage_combo.clear()
|
self.subpage_combo.clear()
|
||||||
self.page_groups = {}
|
self.page_groups = {}
|
||||||
@@ -178,25 +184,48 @@ class MainWindow(QMainWindow):
|
|||||||
# Maybe reset text of hex input
|
# Maybe reset text of hex input
|
||||||
self.hex_input.clear()
|
self.hex_input.clear()
|
||||||
QMessageBox.information(self, "Closed", "File closed.")
|
QMessageBox.information(self, "Closed", "File closed.")
|
||||||
|
self.status_label.setText("Ready")
|
||||||
|
|
||||||
def open_file(self):
|
def open_file(self):
|
||||||
fname, _ = QFileDialog.getOpenFileName(self, "Open T42", "", "Teletext Files (*.t42);;All Files (*)")
|
fname, _ = QFileDialog.getOpenFileName(self, "Open T42", "", "Teletext Files (*.t42);;All Files (*)")
|
||||||
if fname:
|
if fname:
|
||||||
try:
|
try:
|
||||||
self.service = load_t42(fname)
|
self.progress_bar.setVisible(True)
|
||||||
|
self.status_label.setText(f"Loading {os.path.basename(fname)}...")
|
||||||
|
self.progress_bar.setValue(0)
|
||||||
|
|
||||||
|
self.service = load_t42(fname, progress_callback=self.update_progress)
|
||||||
|
self.current_file_path = fname
|
||||||
self.populate_list()
|
self.populate_list()
|
||||||
QMessageBox.information(self, "Loaded", f"Loaded {len(self.service.pages)} pages.")
|
|
||||||
|
self.progress_bar.setVisible(False)
|
||||||
|
self.status_label.setText(f"Loaded {len(self.service.pages)} pages from {os.path.basename(fname)}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
self.progress_bar.setVisible(False)
|
||||||
QMessageBox.critical(self, "Error", f"Failed to load file: {e}")
|
QMessageBox.critical(self, "Error", f"Failed to load file: {e}")
|
||||||
|
self.status_label.setText("Error loading file")
|
||||||
|
|
||||||
def save_file(self):
|
def save_file(self):
|
||||||
fname, _ = QFileDialog.getSaveFileName(self, "Save T42", "", "Teletext Files (*.t42);;All Files (*)")
|
if not self.current_file_path:
|
||||||
if fname:
|
# Logic for "Save As" if path not known, but for T42 we usually overwrite or ask.
|
||||||
try:
|
# To keep it simple, ask every time or track path.
|
||||||
save_t42(fname, self.service)
|
# Let's ask.
|
||||||
QMessageBox.information(self, "Saved", "File saved successfully.")
|
fname, _ = QFileDialog.getSaveFileName(self, "Save T42", "", "Teletext Files (*.t42)")
|
||||||
except Exception as e:
|
if not fname: return
|
||||||
QMessageBox.critical(self, "Error", f"Failed to save file: {e}")
|
self.current_file_path = fname
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.progress_bar.setVisible(True)
|
||||||
|
self.status_label.setText(f"Saving {os.path.basename(self.current_file_path)}...")
|
||||||
|
|
||||||
|
save_t42(self.current_file_path, self.service, progress_callback=self.update_progress)
|
||||||
|
|
||||||
|
self.progress_bar.setVisible(False)
|
||||||
|
self.status_label.setText(f"Saved {len(self.service.pages)} pages to {os.path.basename(self.current_file_path)}")
|
||||||
|
except Exception as e:
|
||||||
|
self.progress_bar.setVisible(False)
|
||||||
|
QMessageBox.critical(self, "Error", f"Failed to save file: {e}")
|
||||||
|
self.status_label.setText("Error saving file")
|
||||||
|
|
||||||
def populate_list(self):
|
def populate_list(self):
|
||||||
self.page_list.clear()
|
self.page_list.clear()
|
||||||
|
|||||||
Reference in New Issue
Block a user