108 lines
3.9 KiB
Python
108 lines
3.9 KiB
Python
import os
|
|
import shutil
|
|
import traceback
|
|
from threading import Timer
|
|
from datetime import datetime
|
|
import uno
|
|
import unohelper
|
|
from com.sun.star.util import XModifyListener
|
|
from com.sun.star.task import XJob, XJobExecutor
|
|
|
|
LOG_FILE = "C:\\Users\\jasonross\\workspace\\LibreOfficeAutoSave\\autosave_debug.log"
|
|
|
|
def log_debug(msg):
|
|
try:
|
|
with open(LOG_FILE, "a") as f:
|
|
f.write(f"[{datetime.now().isoformat()}] {msg}\n")
|
|
except Exception:
|
|
pass
|
|
|
|
log_debug("autosave.py module is being loaded by LibreOffice!")
|
|
|
|
class AutoSaveListener(unohelper.Base, XModifyListener):
|
|
def __init__(self, doc, delay_seconds=1.0):
|
|
self.doc = doc
|
|
self.delay = delay_seconds
|
|
self.timer = None
|
|
log_debug(f"AutoSaveListener initialized for document: {doc}")
|
|
|
|
def modified(self, event):
|
|
if self.timer:
|
|
self.timer.cancel()
|
|
|
|
self.timer = Timer(self.delay, self.execute_safe_save)
|
|
self.timer.start()
|
|
|
|
def execute_safe_save(self):
|
|
try:
|
|
log_debug("Timer expired, attempting save...")
|
|
if self.doc.supportsService("com.sun.star.document.OfficeDocument"):
|
|
if self.doc.hasLocation() and not self.doc.isReadonly():
|
|
file_url = self.doc.getURL()
|
|
log_debug(f"File has location: {file_url}")
|
|
|
|
if file_url.startswith("file:///"):
|
|
system_path = uno.fileUrlToSystemPath(file_url)
|
|
bak_path = os.path.join(os.path.dirname(system_path), f".{os.path.basename(system_path)}.bak")
|
|
try:
|
|
if os.path.exists(system_path):
|
|
shutil.copy2(system_path, bak_path)
|
|
log_debug(f"Created backup at {bak_path}")
|
|
except Exception as e:
|
|
log_debug(f"Backup failed: {e}")
|
|
|
|
self.doc.store()
|
|
log_debug("Document successfully saved.")
|
|
else:
|
|
log_debug("Document is readonly or has no location (not saved yet).")
|
|
except Exception as e:
|
|
log_debug(f"Auto-save exception: {e}\n{traceback.format_exc()}")
|
|
|
|
def disposing(self, event):
|
|
if self.timer:
|
|
self.timer.cancel()
|
|
log_debug("Listener disposed.")
|
|
|
|
g_listeners = {}
|
|
|
|
class AutoSaveJob(unohelper.Base, XJob, XJobExecutor):
|
|
def __init__(self, ctx=None):
|
|
self.ctx = ctx
|
|
log_debug("AutoSaveJob instantiated!")
|
|
|
|
def execute(self, arguments):
|
|
log_debug(f"AutoSaveJob execute() called with args: {arguments}")
|
|
self._attach_listener()
|
|
return ()
|
|
|
|
def trigger(self, args):
|
|
log_debug(f"AutoSaveJob trigger() called with args: {args}")
|
|
self._attach_listener()
|
|
|
|
def _attach_listener(self):
|
|
try:
|
|
ctx = uno.getComponentContext()
|
|
smgr = ctx.ServiceManager
|
|
desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
|
|
doc = desktop.getCurrentComponent()
|
|
|
|
if doc:
|
|
if doc in g_listeners:
|
|
log_debug("Listener already attached to this document.")
|
|
return
|
|
listener = AutoSaveListener(doc, delay_seconds=1.0)
|
|
doc.addModifyListener(listener)
|
|
g_listeners[doc] = listener
|
|
log_debug("Successfully attached listener to current document.")
|
|
else:
|
|
log_debug("No active document found.")
|
|
except Exception as e:
|
|
log_debug(f"Error in AutoSaveJob attach: {e}\n{traceback.format_exc()}")
|
|
|
|
g_ImplementationHelper = unohelper.ImplementationHelper()
|
|
g_ImplementationHelper.addImplementation(
|
|
AutoSaveJob,
|
|
"org.libreoffice.extensions.autosave.AutoSaveJob",
|
|
("com.sun.star.task.Job",),
|
|
)
|