@@ -59,6 +59,7 @@ def __init__(self):
5959 self .current_video_info = None
6060 self .jump_before_ms = 5000
6161 self .last_osl_dir = ""
62+ self .is_modified = False # Track if the dataset has been modified
6263
6364 # Multimedia
6465 self .player = QMediaPlayer (self )
@@ -156,6 +157,7 @@ def load_osl_json_from_file(self, file_path):
156157 self .player .stop () # Stop playback (if running)
157158 self .player .setSource (QUrl .fromLocalFile ("" ))
158159 self .file_path = file_path
160+ self .is_modified = False # Reset modified flag after saving
159161 except Exception as e :
160162 QMessageBox .critical (self , "Error" , f"Failed to load JSON: { e } " )
161163
@@ -168,7 +170,7 @@ def save_osl_json(self):
168170 QMessageBox .StandardButton .Yes | QMessageBox .StandardButton .No
169171 )
170172 if ret != QMessageBox .StandardButton .Yes :
171- return # Cancel saving
173+ return # Cancel saving
172174
173175 if not self .osl_data :
174176 logging .warning ("No data to save." )
@@ -192,6 +194,7 @@ def save_osl_json_from_file(self, file_path):
192194 with open (file_path , 'w' ) as f :
193195 json .dump (self .osl_data , f , indent = 2 )
194196 logging .info (f"Annotations saved to { file_path } " )
197+ self .is_modified = False # Reset modified flag after saving
195198 QMessageBox .information (self , "Saved" , f"Annotations saved to { file_path } " )
196199 except Exception as e :
197200 QMessageBox .critical (self , "Error" , f"Failed to save JSON: { e } " )
@@ -251,6 +254,7 @@ def update_annotation_label(self):
251254 self .annotationModel .index (idx ),
252255 self .annotationModel .index (idx )
253256 )
257+ self .is_modified = True
254258
255259 def set_annotation_time_to_video (self ):
256260 """Set the time of the current annotation to the current video position, resort and refresh."""
@@ -265,6 +269,7 @@ def set_annotation_time_to_video(self):
265269 anns = self .annotationModel .annotations
266270 anns .sort (key = lambda a : a ["position" ])
267271 self .annotationModel .set_annotations (anns )
272+ self .is_modified = True
268273 # Find new index
269274 for new_idx , a in enumerate (anns ):
270275 if a is ann :
@@ -287,6 +292,7 @@ def add_annotation_at_current_time(self):
287292 idx = self .annotationModel .add_annotation (new_annotation )
288293 self .current_video_info ["annotations" ] = self .annotationModel .annotations
289294 self .annotationListView .setCurrentIndex (self .annotationModel .index (idx ))
295+ self .is_modified = True
290296 logging .info (f"Added annotation at { current_time } ms, label={ current_label } " )
291297
292298 def remove_selected_annotation (self ):
@@ -304,6 +310,7 @@ def remove_selected_annotation(self):
304310 return
305311 self .annotationModel .remove_annotation (idx )
306312 self .current_video_info ["annotations" ] = self .annotationModel .annotations
313+ self .is_modified = True
307314 logging .info (f"Removed annotation at idx={ idx } " )
308315
309316 # ---------- Label Management ----------
@@ -319,6 +326,7 @@ def add_label(self):
319326 logging .info (f"Added label: { text } " )
320327 else :
321328 QMessageBox .information (self , "Duplicate" , f"Label '{ text } ' already exists." )
329+ self .is_modified = True
322330
323331 def remove_label (self ):
324332 label = self .labelComboBox .currentText ()
@@ -338,6 +346,7 @@ def remove_label(self):
338346 logging .info (f"Removed label: { label } " )
339347 else :
340348 QMessageBox .warning (self , "Error" , f"Label '{ label } ' not found." )
349+ self .is_modified = True
341350
342351
343352 # ---------- Video Files Management ----------
@@ -358,7 +367,7 @@ def add_video(self):
358367 self .osl_data ["videos" ].append (new_video )
359368 self .osl_data ["videos" ].sort (key = lambda v : v ["path" ])
360369 self .videoModel .set_videos (self .osl_data ["videos" ])
361-
370+ self . is_modified = True
362371 logging .info (f"Added video: { rel_path } " )
363372
364373 def remove_video (self ):
@@ -381,6 +390,7 @@ def remove_video(self):
381390 if self .current_video_info == video :
382391 self .current_video_info = None
383392 self .annotationModel .set_annotations ([])
393+ self .is_modified = True
384394 logging .info (f"Removed video: { video ['path' ]} " )
385395
386396 # ---------- Video Playback Controls ----------
@@ -494,3 +504,32 @@ def load_settings(self):
494504 except (TypeError , ValueError ):
495505 self .jump_before_ms = 5000
496506 self .last_osl_dir = settings .value ("last_osl_dir" , "" )
507+ # from PyQt6.QtWidgets import QMessageBox, QPushButton
508+
509+ def closeEvent (self , event ):
510+ print (self .is_modified , "is modified" )
511+ if self .is_modified :
512+ msg_box = QMessageBox (self )
513+ msg_box .setWindowTitle ("Save Changes?" )
514+ msg_box .setText ("You have unsaved changes. What do you want to do before quitting?" )
515+ save_btn = msg_box .addButton ("Save" , QMessageBox .ButtonRole .AcceptRole )
516+ save_as_btn = msg_box .addButton ("Save As..." , QMessageBox .ButtonRole .ActionRole )
517+ dont_save_btn = msg_box .addButton ("Don't Save" , QMessageBox .ButtonRole .DestructiveRole )
518+ cancel_btn = msg_box .addButton ("Cancel" , QMessageBox .ButtonRole .RejectRole )
519+ msg_box .setIcon (QMessageBox .Icon .Question )
520+ msg_box .exec ()
521+
522+ clicked = msg_box .clickedButton ()
523+ if clicked == save_btn :
524+ self .save_osl_json ()
525+ event .accept ()
526+ elif clicked == save_as_btn :
527+ self .save_as_osl_json ()
528+ event .accept ()
529+ elif clicked == dont_save_btn :
530+ event .accept ()
531+ else : # Cancel or close
532+ event .ignore ()
533+ else :
534+ event .accept ()
535+
0 commit comments