Jump to content

Macros/ScriptForge/HowToJournalizeUpdatesOfDocsExample

From The Document Foundation Wiki


How to journalize the updates that are logged inside a document

Authored by Jean-Pierre Ledure.

  • In this example, every Save command registers, before the save itself, the time when the change took place, who did it and what has been changed.
  • What has been changed is asked to the user with a simple input box. You might also imagine a more complex dialog.
  • Anyway, a new record is inserted at the bottom of an internal file stored in the document. Even when mailed or shared, updates remain registered. Each record is coded as a very basic CSV file.
  • In addition, the log file may be extracted from the document and loaded into a new Calc sheet.

How to run it in BASIC

  1. Create a new document.
  2. Open the Basic IDE
  3. Select the first available blank module
  4. Copy and paste the Basic code
  5. Save the document anywhere
  6. Associate the document's "Save Document" event with the LogUpdate() function
  7. To extract the log file, run manually the ExtractLogFile() Sub

How to run it in Python

Create a new document.

  1. Run APSO
  2. Create a new module, call it 'Module1'
  3. Copy and paste the Python code below
  4. Verify line 17
  5. Save and run the Main() method

Code

REM  SCRIPTFORGE WIKI EXAMPLE
REM 	How to log the updates of a document ?
REM		Minimal required version: LibreOffice 24.2
REM 	Used services
REM 		Document, FileSystem, Platform

Option Explicit

Const logfile = "log/updates-logfile.txt"

'*******************************************************************
'* Associate next Sub with the "Save document" event of the document
'*******************************************************************
Function LogUpdate(Optional event As Object) As Boolean
'	Implements a simple logging of a document's updates:
'		At each Save, an input box is displayed to get a comment
'		related to the last changes.
'		A logging record is created only if the comment is not null.
'	The logging is stored in the document itself. This allows
'	to register updates even when the document is mailed or shared.

Dim doc As Object			'	The actual document as a Document class instance
Dim pf As Object			'	The Platform service
Dim username As String		'	The actual logged user
Dim userdata As Object		'	A Dictionary class instance
Dim logmessage As String	'	A log message given by the user
Dim logrecord As String		'	The record to insert at the bottom of the log file
Dim fs As Object			'	The FileSystem service
Dim filename As String		'	The name of the internal log file
Dim foldername As String	'	The name of the internal log folder
Dim file As Object			'	A TextStream class instance

	GlobalScope.BasicLibraries.loadLibrary("ScriptForge")

	'	Next If makes the script easier to test directly from the Basic IDE
	If IsMissing(event) Then
		Set doc = CreateScriptService("Document", ThisComponent)
	Else
		Set doc = CreateScriptService("DocumentEvent", event)
	End If
	If IsNull(doc) Then Exit Function

	'	Get data to log
	Set pf = CreateScriptService("Platform")
	username = pf.CurrentUser
	userdata = pf.UserData
	logmessage = InputBox("Summarize the changes done today :", "Saving ...")

	'	Do nothing if Cancel was clicked.
	If Len(logmessage) = 0 Then Exit Function

	logrecord = Now() & "," & username & "," _
				& userdata.Item("firstname") & " " & userdata.Item("lastname") & "," _
				& logmessage

	'	Store the record at the bottom of the log file
	Set fs = CreateScriptService("FileSystem")
	filename = fs.BuildPath(doc.filesystem, logfile)
	foldername = fs.GetParentFolderName(filename)
	'	Either make a new file or append to the existing one
	If fs.FileExists(filename) Then
		file = fs.OpenTextFile(filename, iomode := fs.ForAppending)
	Else
		fs.CreateFolder(foldername)
		file = fs.CreateTextFile(filename)
	End If
	file.WriteLine(logrecord)
	file.CloseFile()

	'	Housekeeping
	userdata.Dispose()
	doc.Dispose()

	'	Go ahead with Save
	LogUpdate = False

End Function

'*******************************************************************
'* Execute next Sub to extract the logged records
'*******************************************************************
Sub ExtractLogFile(Optional event As Object)
'	The log file is loaded in an empty Calc sheet
'	The Sub is presumed located in a document's macro library

Dim doc As Object			'	The actual document as a Document class instance
Dim ui As Object			'	The UI service
Dim fs As Object			'	The FileSystem service
Dim filename As String		'	The name of the internal log file
Dim calc As Object			'	A new Calc document as a Calc class instance

	GlobalScope.BasicLibraries.loadLibrary("ScriptForge")

	Set doc = CreateScriptService("Document", ThisComponent)
	Set ui = CreateScriptService("UI")

	'	Is there a log file ?
	Set fs = CreateScriptService("FileSystem")
	filename = fs.BuildPath(doc.filesystem, logfile)
	If Not fs.FileExists(filename) Then
		MsgBox "No log file could be found in your document."
		Exit Sub
	End If

	'	Extract and load the file
	Set calc = ui.CreateDocument("Calc")	'	Create a new Calc document
	calc.ImportFromCSVFile(filename, "A1")

	'	Housekeeping
	doc.Dispose()
	calc.Dispose()

End Sub
# coding: utf-8
from __future__ import unicode_literals

from scriptforge import CreateScriptService

###  SCRIPTFORGE WIKI EXAMPLE
### 	How to log the updates of a document ?
###		Minimal required version: LibreOffice 24.2
### 	Used services
### 		Document, FileSystem, Platform

logfile = 'log/updates-logfile.txt'

basic = CreateScriptService('Basic')
pf = CreateScriptService('Platform')
fs = CreateScriptService('FileSystem')
ui = CreateScriptService('UI')

# *******************************************************************
# * Associate next def with the 'Save document' event of the document
# *******************************************************************
def logupdate(event = None):
	# 	Implements a simple logging of a document's updates:
	# 		At each Save, an input box is displayed to get a comment
	# 		related to the last changes.
	# 		A logging record is created only if the comment is not null.
	# 	The logging is stored in the document itself. This allows
	# 	to register updates even when the document is mailed or shared.

	# doc							The actual document as a Document class instance
	# username						The actual logged user
	# userdata						A dict(ionary)
	# logmessage					A log message given by the user
	# logrecord						The record to insert at the bottom of the log file
	# filename						The name of the internal log file
	# foldername					The name of the internal log folder
	# file							A TextStream class instance

	# 	doc is derived from the input event
	doc = CreateScriptService('DocumentEvent', event)
	if doc is None:
		return

	# 	Get data to log
	username = pf.CurrentUser
	userdata = pf.UserData
	logmessage = basic.InputBox('Summarize the changes done today :', 'Saving ...')

	# 	Do nothing if Cancel was clicked.
	if len(logmessage) == 0:
		return False

	logrecord = str(basic.Now()) + ',' + username + ',' \
			+ userdata['firstname'] + ' ' + userdata['lastname'] + ',' \
			+ logmessage

	# 	Store the record at the bottom of the log file
	filename = fs.BuildPath(doc.filesystem, logfile)
	foldername = fs.GetParentFolderName(filename)
	# 	Either make a new file or append to the existing one
	if fs.FileExists(filename):
		file = fs.OpenTextFile(filename, iomode = fs.ForAppending)
	else:
		fs.CreateFolder(foldername)
		file = fs.CreateTextFile(filename)
	file.WriteLine(logrecord)
	file.CloseFile()

	# 	Housekeeping
	doc.Dispose()

	# 	Go ahead with Save
	return False


# *******************************************************************
# * Execute next Sub to extract the logged records
# *******************************************************************
def extractlogfile(event = None):
	# 	The log file is loaded in an empty Calc sheet

	# doc						The actual document as a Document class instance
	# filename					The name of the internal log file
	# calc						A new Calc document as a Calc class instance

	doc = CreateScriptService('Document', basic.ThisComponent)

	# 	Is there a log file ?
	filename = fs.BuildPath(doc.FileSystem, logfile)
	if fs.FileExists(filename) is False:
		basic.MsgBox('No log file could be found in your document.')
		return

	# 	Extract and load the file
	calc = ui.CreateDocument('Calc')  # Create a new Calc document
	calc.ImportFromCSVFile(filename, 'A1')

	# 	Housekeeping
	doc.Dispose()
	calc.Dispose()


g_exportedScripts = (logupdate, extractlogfile)

if __name__ == "__main__":
	logupdate()


See also