Forum rules
For sharing working examples of macros / scripts. These can be in any script language supported by OpenOffice.org [Basic, Python, Netbean] or as source code files in Java or C# even - but requires the actual source code listing. This forum is not for asking questions about writing your own macros.

The purpose of this macro that I adapted from other code snippets found in this forum is to create a copy of the current document in a separate folder, with a timestamp added to the filename, in order to simulate a kind of versionning. This macro works with Writer, Calc, Draw and Impress documents.

For example, if the current document is MyTest.odt, each time you run the macro a copy will be saved in the folder C:\BackupDocs (change the default folder name in the code, around line 57) with the name MyTest_2009-10-10_172536.odt.

In order to use this code, copy it under MyMacros / Standard library, and it is easier to create a new button in the toolbar and associate it with the macro AutomaticBackup (you unfortunately have to do this button allocation in each editor: Calc, Draw, Impress and Writer). After that, simply press this button from time to time (I recommend every 30 minutes) and you will never lose much of your work anymore!

(For advanced users, this macro can make several copies of the document, in different formats. For example, you can save a Writer document in the format .odt, .doc, .swx, etc. Look into the code how add multiple versions.)

In case of improvement or bug fixing, I will always update the code in this first post. Thanks in advance for your comments!

Sub AutomaticBackup'------------------------------------------------------------------------' This macro saves the document plus a copy, in a backup folder.' It adds to the document a TimeStamp, so the filename will be:' "mydocument_YYYYMMDD_HHMMSS.xxx"' where YYYY represents the current year, MM the month, DD the day,' HHMMSS the time in hours, minutes and seconds''------------------------------------------------------------------------' History'------------------------------------------------------------------------' v 1.3 2009-10-10 Now works with Windows XP and Linux (Ubuntu)' file path format containing "/" or "\"'' v 1.2 2007-04-16 Add several new filters and make the selection' of which filters to use for backup' relatively easy for the User. Allow save of' the document in case it is not yet saved.'' v 1.1.1 2007-04-12 Improve the handling of the path, with possibility' of relative path (from current file path) or' even empty path (same folder as current file).'' v 1.1.0 2007-04-10 Work with the four main document types of OOo' (Writer, Calc, Impress and Draw). '------------------------------------------------------------------------

Dim oDoc as Object Dim oDocNew as Object Dim sDocURL as String Dim sDocNameWithFullPath as String Dim sNewURL as String Dim sPathBackupFolder as String Dim sSaveToURL as String Dim sTimeStamp as String Dim sDocName as String Dim i as Long Dim j as Long Dim k as Long Dim sDocType as String Dim oDispatcher as Object Dim sBackup(200) as String Dim sSlash as String Dim sOtherSlash as String Dim s as String

' Change the line below to adapt the path of the ' backup folder. It can be: ' * A full path (ex. "C:\My Documents\BackupFolder") ' * A relative path starting with a \ (ex. "\Backup") ' * Empty sPathBackupFolder = "C:\BackupDocs"

' This is the array that defines which extensions to use for ' backup purposes, based on the type of document ' Simply add the word "BACKUP" (without quotes) between the first ' two vertical bars and the program will behave accordingly ' Each string contains five parameters which are: ' - Module in OOo ' - The word BACKUP or an empty string ' - A free text describing the format ' - The extension of the file ' - The name of the filter that will write the file in the proper format i = 0

' I strongly recommend that you keep these four lines as they are ' which means that the backup copy will retain all the formatting ' created in OOo as they are done using native OOo file types i = i + 1 : sBackup(i) = "Calc|BACKUP|Open Document Spreadsheet|ods|Calc8" i = i + 1 : sBackup(i) = "Draw|BACKUP|Open Document Drawing|odd|Draw8" i = i + 1 : sBackup(i) = "Impress|BACKUP|Open Document Presentation|odp|Impress8" i = i + 1 : sBackup(i) = "Writer|BACKUP|Open Document Text|odt|Writer8"

' If this is a new document, we must save it first ' in order to later get its path and filter type oDoc = ThisComponent If Not(oDoc.hasLocation) Then oDocNew = ThisComponent.CurrentController.Frame oDispatcher = createUnoService("com.sun.star.frame.DispatchHelper") oDispatcher.executeDispatch(oDocNew, ".uno:SaveAs", "", 0, array()) End If

' If the document still has no location, then we ' display an understandable error message If Not(oDoc.hasLocation) Then Msgbox "Your document has NOT been saved, and NO backup copy will be created. " & _ "May be you tried to save your document on a folder where you cannot write, " & _ "or you tried to override a file already in use. Please check and run again." Exit Sub End If

' Determine whether the path should be written with ' "/" or "\" to indicate the hierarchy of folders ' (Modification of v1.3 to work with Windows and Ubuntu) If Instr(1, sDocNameWithFullPath, "/") > 0 Then sSlash = "/" sOtherSlash = "\" Else sSlash = "\" sOtherSlash= "/" End If sDocName = GetFileName(sDocNameWithFullPath, sSlash)

' If the backupfolder variable is empty, or starts with a \ or / ' indicating a sub-folder, then we will use the ' current folder of the document and append the sub-folder If sPathBackupFolder = "" or Left(sPathBackupFolder, 1) = sSlash Then i = Len(sDocNameWithFullPath) While Mid(sDocNameWithFullPath, i, 1) <> sSlash i = i - 1 Wend sPathBackupFolder = Left(sDocNameWithFullPath, i - 1) & sPathBackupFolder End If

' Check if the backup folder exists, if not we create it On Error Resume Next MkDir sPathBackupFolder On Error Goto 0

' Add a slash at the end of the path, ' if not already present If Right(sPathBackupFolder, 1) <> sSlash Then sPathBackupFolder = sPathBackupFolder & sSlash End If

' Save the current document only if it has changed, ' is not new (has been saved before) and is not read only If oDoc.isModified and oDoc.hasLocation and Not(oDoc.isReadOnly) Then oDoc.store() End If

' For each file filter, let's see whether we should ' create a backup copy or not i = 1 While sBackup(i) <> "" If GetString(sBackup(i), "|", 2) = "BACKUP" Then

Function MakePropertyValue(Optional sName As String, Optional sValue) As com.sun.star.beans.PropertyValue'-------------------------------------------------------------------' Create and return a new com.sun.star.beans.PropertyValue'-------------------------------------------------------------------

Dim oPropertyValue As New com.sun.star.beans.PropertyValue

If Not IsMissing(sName) Then oPropertyValue.Name = sName EndIf

If Not IsMissing(sValue) Then oPropertyValue.Value = sValue EndIf

MakePropertyValue() = oPropertyValue

End Function

Function GetFileName(byVal sNameWithFullPath as String, byval sSlash as String) as String'-------------------------------------------------------------------' Return the name of the file without path nor extension from a string' that contains the full name (including path) of a file'-------------------------------------------------------------------

Dim i as Long Dim j as Long

GetFileName = ""

' Let's search from the end of the full name ' a "." that will indicate the end of the ' file name and the beginning of the extension For i = Len(sNameWithFullPath) To 1 Step -1 If Mid(sNameWithFullPath, i, 1) = "." Then

' We have found a ".", so now we continue ' backwards and search for the path delimiter "\" or "/" For j = i - 1 to 1 Step -1 If Mid(sNameWithFullPath, j, 1) = sSlash Then

' We have found it, the file name is the ' piece of string between the two GetFileName = Mid(sNameWithFullPath, j + 1, i - j - 1) j = 0 i = 0 End If Next j End If Next i

End Function

Function GetString(byVal sInput as String, byVal sDelimiter as String, ByVal iPosition as Long) as String'-------------------------------------------------------------------' This function returns a substring from sInput, located after' the iPositionth of sDelimiter and the next occurence' of sDelimiter or the end of the string, whatever occurs first'-------------------------------------------------------------------

Dim i as Long Dim j as Long Dim k as Long

' Let's add a delimiter at the beginning and end of the string ' it makes the processing easier for the first and last portion ' of the string sInput = sDelimiter & sInput & sDelimiter

Function GetFilterType(byVal sFileName as String) as String'-------------------------------------------------------------------' This function returns the filter type of a file' Credit: http://www.oooforum.org/forum/viewtopic.phtml?t=52047'-------------------------------------------------------------------

My friend, thank you very much!That's exactly what I was looking for and I registered here just to express my thanks.

I'm in the middle of my monography, and sometimes I need to go back and forth between versions... Which I had to do manually...Besides, the versioning control of OO/LO isn't intuitive and has many risks... my odt got corrupted and I lost all the backups.

For that reason, I was implementing a macro for doing something like that myself since last week.Everytime I hit save, my document would be backed by it. It was working somehow, but I was having problems like to figure syntax and how to determine the relative path of the document. I know a little bit of javascript and a little of python, but I'm really a newbie.

Thank you for posting this! This is what I was looking for.I have pointed the saving to my cloud sync folder and instead of creating the button, I decided to trigger the macro on saving the file connecting it to an event (save document was just fine to me, I save pretty often). So now, each time I save I have a timestamped copy created and copied to my cloud space....

The only further question I have, as I haven't been able to find a solution yet, is if the backup file saved via this macro can be made read-only? Being able to do that would solve the problem I've been fighting with for awhile now.