Feat: Add Unsaved Changes warning on Exit/Close/Open
This commit is contained in:
@@ -29,6 +29,7 @@ class MainWindow(QMainWindow):
|
|||||||
self.clipboard = [] # List of (row, data_bytes)
|
self.clipboard = [] # List of (row, data_bytes)
|
||||||
self.undo_stack = []
|
self.undo_stack = []
|
||||||
self.redo_stack = []
|
self.redo_stack = []
|
||||||
|
self.is_modified = False
|
||||||
|
|
||||||
# UI Components
|
# UI Components
|
||||||
self.central_widget = QWidget()
|
self.central_widget = QWidget()
|
||||||
@@ -130,6 +131,40 @@ class MainWindow(QMainWindow):
|
|||||||
# Menus
|
# Menus
|
||||||
self.create_menus()
|
self.create_menus()
|
||||||
|
|
||||||
|
def set_modified(self, modified: bool):
|
||||||
|
self.is_modified = modified
|
||||||
|
title = "Teletext Editor"
|
||||||
|
if self.current_file_path:
|
||||||
|
title += f" - {os.path.basename(self.current_file_path)}"
|
||||||
|
else:
|
||||||
|
title += " - Untitled"
|
||||||
|
|
||||||
|
if self.is_modified:
|
||||||
|
title += " *"
|
||||||
|
self.setWindowTitle(title)
|
||||||
|
|
||||||
|
def maybe_save_changes(self) -> bool:
|
||||||
|
if not self.is_modified:
|
||||||
|
return True
|
||||||
|
|
||||||
|
ret = QMessageBox.warning(self, "Unsaved Changes",
|
||||||
|
"The document has been modified.\nDo you want to save your changes?",
|
||||||
|
QMessageBox.StandardButton.Save | QMessageBox.StandardButton.Discard | QMessageBox.StandardButton.Cancel)
|
||||||
|
|
||||||
|
if ret == QMessageBox.StandardButton.Save:
|
||||||
|
self.save_file()
|
||||||
|
return True # check if save succeeded? save_file catches exceptions but we might want to check
|
||||||
|
elif ret == QMessageBox.StandardButton.Discard:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False # Cancel
|
||||||
|
|
||||||
|
def closeEvent(self, event):
|
||||||
|
if self.maybe_save_changes():
|
||||||
|
event.accept()
|
||||||
|
else:
|
||||||
|
event.ignore()
|
||||||
|
|
||||||
def update_progress(self, current, total):
|
def update_progress(self, current, total):
|
||||||
self.progress_bar.setMaximum(total)
|
self.progress_bar.setMaximum(total)
|
||||||
self.progress_bar.setValue(current)
|
self.progress_bar.setValue(current)
|
||||||
@@ -220,6 +255,9 @@ class MainWindow(QMainWindow):
|
|||||||
self.subpage_combo.setCurrentIndex(new_index)
|
self.subpage_combo.setCurrentIndex(new_index)
|
||||||
|
|
||||||
def close_file(self):
|
def close_file(self):
|
||||||
|
if not self.maybe_save_changes():
|
||||||
|
return
|
||||||
|
|
||||||
# Reset everything
|
# Reset everything
|
||||||
self.service = TeletextService()
|
self.service = TeletextService()
|
||||||
self.current_page = None
|
self.current_page = None
|
||||||
@@ -231,10 +269,19 @@ class MainWindow(QMainWindow):
|
|||||||
self.canvas.set_page(None)
|
self.canvas.set_page(None)
|
||||||
# Maybe reset text of hex input
|
# Maybe reset text of hex input
|
||||||
self.hex_input.clear()
|
self.hex_input.clear()
|
||||||
|
|
||||||
|
self.undo_stack.clear()
|
||||||
|
self.redo_stack.clear()
|
||||||
|
|
||||||
QMessageBox.information(self, "Closed", "File closed.")
|
QMessageBox.information(self, "Closed", "File closed.")
|
||||||
self.status_label.setText("Ready")
|
self.status_label.setText("Ready")
|
||||||
|
self.set_modified(False)
|
||||||
|
|
||||||
|
|
||||||
def open_file(self):
|
def open_file(self):
|
||||||
|
if not self.maybe_save_changes():
|
||||||
|
return
|
||||||
|
|
||||||
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:
|
||||||
@@ -248,6 +295,10 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
self.progress_bar.setVisible(False)
|
self.progress_bar.setVisible(False)
|
||||||
self.status_label.setText(f"Loaded {len(self.service.pages)} pages from {os.path.basename(fname)}")
|
self.status_label.setText(f"Loaded {len(self.service.pages)} pages from {os.path.basename(fname)}")
|
||||||
|
|
||||||
|
self.undo_stack.clear()
|
||||||
|
self.redo_stack.clear()
|
||||||
|
self.set_modified(False)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.progress_bar.setVisible(False)
|
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}")
|
||||||
@@ -274,6 +325,7 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
self.progress_bar.setVisible(False)
|
self.progress_bar.setVisible(False)
|
||||||
self.status_label.setText(f"Saved {len(self.service.pages)} pages to {os.path.basename(self.current_file_path)}")
|
self.status_label.setText(f"Saved {len(self.service.pages)} pages to {os.path.basename(self.current_file_path)}")
|
||||||
|
self.set_modified(False)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.progress_bar.setVisible(False)
|
self.progress_bar.setVisible(False)
|
||||||
QMessageBox.critical(self, "Error", f"Failed to save file: {e}")
|
QMessageBox.critical(self, "Error", f"Failed to save file: {e}")
|
||||||
@@ -349,6 +401,7 @@ class MainWindow(QMainWindow):
|
|||||||
# Limit stack size
|
# Limit stack size
|
||||||
if len(self.undo_stack) > 50:
|
if len(self.undo_stack) > 50:
|
||||||
self.undo_stack.pop(0)
|
self.undo_stack.pop(0)
|
||||||
|
self.set_modified(True)
|
||||||
|
|
||||||
def undo(self):
|
def undo(self):
|
||||||
if not self.undo_stack:
|
if not self.undo_stack:
|
||||||
@@ -362,6 +415,7 @@ class MainWindow(QMainWindow):
|
|||||||
snapshot = self.undo_stack.pop()
|
snapshot = self.undo_stack.pop()
|
||||||
self.restore_snapshot(snapshot)
|
self.restore_snapshot(snapshot)
|
||||||
self.status_label.setText("Undone.")
|
self.status_label.setText("Undone.")
|
||||||
|
self.set_modified(True)
|
||||||
|
|
||||||
def redo(self):
|
def redo(self):
|
||||||
if not self.redo_stack:
|
if not self.redo_stack:
|
||||||
@@ -375,6 +429,7 @@ class MainWindow(QMainWindow):
|
|||||||
snapshot = self.redo_stack.pop()
|
snapshot = self.redo_stack.pop()
|
||||||
self.restore_snapshot(snapshot)
|
self.restore_snapshot(snapshot)
|
||||||
self.status_label.setText("Redone.")
|
self.status_label.setText("Redone.")
|
||||||
|
self.set_modified(True)
|
||||||
|
|
||||||
def restore_snapshot(self, snapshot: Page):
|
def restore_snapshot(self, snapshot: Page):
|
||||||
# We need to update self.current_page content
|
# We need to update self.current_page content
|
||||||
|
|||||||
Reference in New Issue
Block a user