| View previous topic :: View next topic |
| Author |
Message |
JohnV Administrator

Joined: 07 Mar 2003 Posts: 8979 Location: Lexinton, Kentucky, USA
|
Posted: Wed Jul 12, 2006 6:48 am Post subject: AutoSave template child doc to defined subdirectory |
|
|
Several people have complained about the necessity of having to traverse a long directory tree to save a file to its intended directory and I got tired of it too. If you create files from templates properly saved in OOo's template directory this macro provides a way to solve the problem. The macro should be saved in My Macros - Standard or some other global library and not in any of your templates. I have attached mine to the Ctrl+S key combo as I don't normally use that for a Save.
You need to edit the macro's first set of User Variables in the first subroutine to define a basic home (top level) directory for saving OOo files. Normally this will be your default OOo directory.
From this home directory the macro provides two methods to specify one or more subdirectory levels to which the file should be saved. Both methods can be used together.
For the first method look at the “Case” statement lines in the second set of User Variables in the first subroutine. The first such “Case” line looks this,
Case "LetterHead" : SubDir = "Letters"
where LetterHead is the name of the template used and Letters specifies the subdirectory to save it in. The second such “Case” line show an example of going 2 two subdirectories deep. There is no reason you can't go deeper, just note that you do not use a slash before or after the subdirectories but you do between them. You can add additional “Case” lines and, of course, modify the sample ones.
The first method will require you to edit the macro any time you want to add additional templates to the macro. The second method avoids this.
The second method actually defines the one or more subdirectory levels as part of the template name. In this regard note that in the first set of User Variables I have defined the back quote (upper left key, next to “1”) as the Divider. You may define a different Divider but it should be a unique character and allowable in file names for your operating system.* To achieve the same result as the two “Case” lines in the macro you would name your templates:
LetterHead`Letters
and
Invoice`Client`Invoices
* If you use a period as the Divider the the last character of the template name must be a period, e.g., LetterHead.Letters. because OOo will truncate the last period and any characters following it thinking it's an extension.
You can have the same basic template saving to several different locations with something like:
LetterHead`Personal`Letters
LetterHead`Client`Letters
LetterHead`Suppliers`Letters
If you specify one or more subdirectories levels that do not exist the macro creates them so be very careful when warned this is about to happen or you may lose track of where your files end up. For example, I used “Documents and Setting” instead of “Documents and Settings” in the definition of my home directory and missed it when warned because I actually had another new directory in play at the same time.
The macro will warn you if you try to overwrite an existing file and you can do so or change the file name or path.
If you run the macro against a file that it is not setup to handle then you will be notified of the unintended use but will be allowed to continue so a Save or Save As can be finished. (To avoid such notifications comment out the first “If” through “EndIf” code block of the SaveFile subroutine, but I suggest you let this work for a while.)
The macro doesn't notify you when it's finished but, unless you run it against an existing file and don't change the name, you will see the file name change on the top line of the screen.
The macro should handle templates of type Writer, Calc, Draw, Presentation and HTML but has mostly been tested with Writer. DataBase, Master Document and Formula files do not support templates.
The program assumes the use of OOo2.x.x but should work with OOo1.1.x if you change the file extensions in the GetFileTypeOrExtension function. I have no reason to think the macro will not work under Linux, etc., but it has only been tested under Window98 & W2K.
Please let me know if you find a bug. However, my hope is that you just get saved a lot of aggravation. | Code: |
Sub AutoSaveTemplateChild 'Saves template child to defined directory.
'Version 1 July 11, 2006 by John C. Vigor, Jr.
'>>>>>>>>>>>>>> USER VARIABLES <<<<<<<<<<<<<
REM Define some basic home directory for saving OOo files, normally
REM your default OOo directory.
HomeDir = "C:\Documents and Settings\JohnV\My Documents"
Divider = "`" 'Unique character to seperate file name from save subdirectory.
'>>> END USER VARIABLES - BUT MORE BELOW <<<
On Error Goto ErrHand
condition = 1 'Normal use of macro.
oDoc = ThisComponent
Url = oDoc.getURL
TemplateName = oDoc.DocumentInfo.Template
PathSep = getPathSeparator
b$ = " However, you may continue."
If TemplateName = "" And Url = "" then
'Child created from template in normal directory or from OOo's
'built in default template as opposed to a users Default Template.
a$ = "This macro is intended to work with documents created from a"
a$ = a$ & " template stored in OOo's template directory." & b$
SaveUrl = HomeDir & PathSep
SaveFile(oDoc,SaveUrl,condition,a$) : End
ElseIF Url <> "" then
condition = 2 'Existing file.
a$ = "This macro is not intended for use with an exiting file." & b$
SaveUrl = ConvertFromURL(Url)
SaveFile(oDoc,SaveUrl,condition,a$) : End
EndIf
Select Case TemplateName
'>>>>>>>>>>>>>> USER VARIABLES <<<<<<<<<<<<<
REM "Case" statements below are case sensitive, e.g., Letterhead below would fail!
REM You may modify and/or add "Case" lines.
Case "LetterHead" : SubDir = "Letters"
Case "Invoice" : SubDir = "Client\Invoices"
'>>>>>>>>>>> END OF USER VARIABLES <<<<<<<<<
Case Else
sp = Split(TemplateName,Divider)
If uBound(sp) > 0 then
sp(0) = ""
Else
a$ = "This macro is not intended to work with a file created from the '"
a$ = a$ & sp(0) & "' template." & b$
SaveUrl = HomeDir & PathSep
SaveFile(oDoc,SaveUrl,condition,a$) : End
EndIf
SubDir = Join(sp,PathSep)
SubDir = Right(SubDir,Len(SubDir)-1)
End Select
SaveUrl = HomeDir & PathSep & SubDir & PathSep
SaveFile(oDoc,SaveUrl,condition,a$)
END 'Normal program end.
ErrHand:
If Err = 423 then
e$ = "Possibly no file is open."
EndIf
er$ = "Error #" & Err & " '" & Error$ & "' occurred in line #" & Erl
er$ = er$ & Chr(13) & Chr(13) & e$
MsgBox (er$,,"AN ERROR OCCURRED")
End Sub
Sub SaveFile(oDoc,SaveUrl,condition,a$)
If a$ <> "" then
iAns = MsgBox(a$,1,"Unintended macro use.")
If iAns = 2 then End
EndIf
If Not FileExists(converttoUrl(SaveURL)) then
a$ = "Do you intend to create a new file folder(s)?" & Chr(13)
a$ = a$ & "New folder(s) = " & SaveUrl
iAns = MsgBox (a$,4,"WARNING!")
If iAns = 7 then End
EndIf
GetFileName:
Do
If condition = 2 then 'It's an existing file.
a$ = "You may change the file name or path below."
Else 'It's a new file.
a$ = "Append a file name, without extension, to the path below." & Chr(13)
a$ = a$ & Chr(13) & "You may also modify the path."
EndIf
Copy = SaveUrl
SaveUrl = InputBox(a$,"PREPARING TO SAVE.", SaveUrl)
If SaveUrl = "" then End
Loop While SaveUrl = Copy And condition <> 2
If condition <> 2 then 'It's not an existing file.
ext = GetFileTypeOrExtension(oDoc,"Ext")
SaveUrl = SaveUrl & ext
EndIf
If FileExists(SaveUrl) then
condition = 2 'Existing file.
iAns = MsgBox ("File Exists. Overwrite?",3,"WARNING!")
If iAns = 2 then End
If iAns = 7 then SaveUrl = Copy : goto GetFileName
EndIf
oDoc.storeAsUrl(convertToURL(SaveUrl),Array())
End Sub
Function GetFileTypeOrExtension(oDoc, Optional GetWhat as String)
If isMissing(GetWhat) then GetWhat = "Ext"
aray = oDoc.getSupportedServiceNames
d = "Document"
supported = Array("Text" & d,"Spreadsheet" & d,"Drawing" & d,"Web" & d,_
"Presentation" & d,"Database" & d,"Global" & d,"FormulaProperties")
Found = false
For I = 0 to ubound(aray)
For II = 0 to uBound(supported)
If Instr(aray(I),supported(II)) > 0 then Found = true : Exit For
Next
If Found = true then Exit For
Next
If Not Found then Msgbox("Unknown document type. Quiting.") : End
Select Case II
Case 0 : ext = ".odt"
Case 1 : ext = ".ods"
Case 2 : ext = ".odg"
Case 3 : ext = ".html"
Case 4 : ext = ".odp"
Case 5 : ext = ".odb" 'Templates not supported.
Case 6 : ext = ".odm" 'Templates not supported.
Case 7 : ext = ".odf" 'Templates not supported.
End Select
If GetWhat = "Ext" then
GetFileTypeOrExtension = ext
Else GetFileTypeOrExtension = Supported(II)
EndIf
End Function |
|
|
| Back to top |
|
 |
Ken Ryan Newbie

Joined: 15 Mar 2005 Posts: 2
|
Posted: Wed Jul 12, 2006 11:20 am Post subject: |
|
|
Hi, John!
[It doesn't "feel" like this reply is really appropriate as a thread, but since your email specifically requested I post...]
I admit I haven't tried running your macro, but it doesn't sound like it'd solve my gripes. You're essentially making a template<->directory correlation.
I have only a couple templates that I use in lots of different projects. My directories are organized by project. I therefore end up traversing from the starting point configured in OOo down to where I actually want to place the file. I mitigated this by making the default location the parent of all my project trees, which helps about halfway.
Ideally I'd like in the file path configuration box to be able to check a box saying "just remember where I saved the last one and start there". I tend to work in one project for several weeks or months, then move to another. Some windows programs have that last-used-directory behavior already. It still wouldn't be a complete solution, but I think the only way to get better than a mind-reading library.
As it is, I usually don't use templates stored in OOo. I just have a copy of the template itself in the individual project dir where I can open it in-place. (Naturally I end up with 35 versions of my template, nothing's perfect). _________________ - ken |
|
| Back to top |
|
 |
JohnV Administrator

Joined: 07 Mar 2003 Posts: 8979 Location: Lexinton, Kentucky, USA
|
Posted: Thu Jul 13, 2006 2:55 pm Post subject: |
|
|
| Quote: | | As it is, I usually don't use templates stored in OOo. | Well you are a man after my own heart as I normally save my templates in the directory to which they relate. Unfortunately a child of such a template has an empty TemplateName property and an empty URL property so I couldn't use either in the macro.
You might try this. Store the equivalent of a template as an ordinary .odt file. Open the file, do what you need, do a Save As and change the Name. Save As will offer you the subdirectory that you opened the file from and your "template" will remain as it was. The macro would do the same thing for you but simply isn't needed. The only trick is to remember to do the Save As so you don't ruin the "template". I suspect you could record a Save As macro and attach it to the open document event.
Hum, may have to change my own approach. You lose the ability to edit the template sytles and apply those changes to documents previously created from a template "properly" stored but I have never found a need for that in my work. |
|
| Back to top |
|
 |
Villeroy Super User


Joined: 04 Oct 2004 Posts: 10065 Location: Germany
|
Posted: Fri Jul 14, 2006 2:12 pm Post subject: |
|
|
| Quote: | | Well you are a man after my own heart as I normally save my templates in the directory to which they relate. |
So do I. My documents and OOo profile are saved on the same Linux filesystem, so I can use hard links (undistinguishable filesystem entries, pointing to the same file content). Symbolic links (links with information about the "real file") are shown in the template-organizer when the link points to some "real file" in a template directory. In either case I get a DocumentInfo.TemplateName. The latter should work with Windows-links as well. _________________ Rest in peace, oooforum.org
Get help on http://forum.openoffice.org |
|
| Back to top |
|
 |
JohnV Administrator

Joined: 07 Mar 2003 Posts: 8979 Location: Lexinton, Kentucky, USA
|
Posted: Sat Jul 15, 2006 11:42 am Post subject: |
|
|
| Quote: | | The latter should work with Windows-links as well. | Well the only link I know in Windows is a shortcut so I tried one to a template stored in a normal directory and my File > Properties > Template entry came up empty. I thought Windows was going to try to have an equivalent to Linux links but if I can do it in W2K I don't know how.
Have you used the macro with "stored were it makes sense" templates and, if so, is it of value to you or have I justed wasted my time? |
|
| Back to top |
|
 |
Villeroy Super User


Joined: 04 Oct 2004 Posts: 10065 Location: Germany
|
Posted: Mon Jul 17, 2006 9:30 am Post subject: |
|
|
| JohnV wrote: | | Quote: | | The latter should work with Windows-links as well. | Well the only link I know in Windows is a shortcut so I tried one to a template stored in a normal directory and my File > Properties > Template entry came up empty. I thought Windows was going to try to have an equivalent to Linux links but if I can do it in W2K I don't know how.
Have you used the macro with "stored were it makes sense" templates and, if so, is it of value to you or have I justed wasted my time? |
To be honest: I don't like your macro because it shows too many message boxes and it requires hard coded mapping of template names to subdirectories.
The following code is a simple draft. You can set any global document-event to Sub setLastPath in order to store the path of a document in a global string var globLastDir.
sub MySaveDocumentAs shows a save-as dialog with globLastDir as default directory and template name as default file name.
If the document has a userdefined file info "TryPath" with some value like "subdir/subsubdir/", it tries to set this subdirectory as default path of the file picker.
I use to store globals in a separate module, so they survive code changes.
| Code: |
REM ***** BASIC *****
Global globLastDir$
|
| Code: |
REM ***** BASIC *****
Option Explicit
Sub MySaveDocumentAs()
'calls: global var globLastDir, getURLPath, getUserFieldValue, PickFileName, setLastPath
'name of a userdefined property (File>Properties>Tab:"User Defined">button "Info Fields ..."
'It's value should specifiy some preferred sub-dir in URL notation without leading slash ("sub/dir", "sub/dir/")
Const cTry$ = "TryPath"
Dim SaveUrl$,sLastDir$,subDir$,sConcat$,sTemplate$
'if globLastDir is unset, set to user's default work-directory:
if globLastDir = "" then globLastDir = getWorkDir
'get a preferred sub-directory suffix:
subDir = getUserFieldValue(thisComponent,cTry)
If len(thisComponent.URL) > 0 then
'if already saved then use this path as default:
sLastDir = getURLPath(thisComponent.URL)
else
'use globLastDir
sLastDir = globLastDir
endif
'minimal checking:
if Not(fileexists(sLastDir)) then sLastDir = getWorkDir
sConcat = sLastDir & subDir
if Not(fileexists(sConcat)) then sConcat = sLastDir
sTemplate = thisComponent.DocumentInfo.Template
SaveUrl = PickFileName(cFolder:=sConcat,cFileName:=sTemplate ,sTitle:="MySaveDocumentAs()")
If len(SaveUrl) > 0 then
thisComponent.storeAsUrl(SaveUrl,Array())
endif
End Sub
Function getWorkDir() as string
DIm oSrv
oSrv=createUnoService("com.sun.star.util.PathSettings")
getWorkDir = oSrv.Work &"/"
End Function
'set Tools>Customize>Event "Document has been saved As" and/or "Document has been saved"
Sub setLastPath()
'calls: getURLPath
Dim sURL$
sURL = thisComponent.getURL
if len(sURL) > 0 then globLastDir = getURLPath(sURL)
' msgbox globLastDir,0,"setLastPath"
End Sub
Function getUserFieldValue(oDoc,sName$) as String
'calls: none
Dim i%,sVal$
with oDoc.DocumentInfo
for i = 0 to .getUserfieldCount -1
if .getUserfieldName(i) = sName then
sVal = .getUserFieldValue(i)
exit for
endif
next
end with
getUserFieldValue = sVal
End Function
|
Stolen from http://www.oooforum.org/forum/viewtopic.phtml?t=27188&highlight=save+filepicker and modified:
| Code: |
Function PickFileName( cFolder, cFileName, sTitle$)as string
oFilePickerDlg = createUnoService( "com.sun.star.ui.dialogs.FilePicker" )
sFilePickerArgs = Array(com.sun.star.ui.dialogs.TemplateDescription.FILESAVE_AUTOEXTENSION_PASSWORD )
With oFilePickerDlg
.setTitle(sTitle)
sDirectory = cFolder
.Initialize ( sFilePickerArgs() )
.SetDisplayDirectory (sDirectory)
.SetDefaultName (cFileName)
' .AppendFilter( "All files (*.*)", "*.*" )
' .AppendFilter( "OpenDocument Text (.odt)", "*.odt" )
' .AppendFilter( "OpenDocument Text Template (.ott)", "*.ott" )
' .SetCurrentFilter( "OpenDocument Text (.odt)" )
.SetValue(com.sun.star.ui.dialogs.ExtendedFilePickerElementIds.CHECKBOX_AUTOEXTENSION, 0, true)
.SetValue(com.sun.star.ui.dialogs.ExtendedFilePickerElementIds.CHECKBOX_PASSWORD, 0, false)
'.EnableControl(com.sun.star.ui.dialogs.ExtendedFilePickerElementIds.CHECKBOX_PASSWORD, false)
End With
' Unnecessary, the dialog defaults to having multi-select turned off.
' oFilePickerDlg.setMultiSelectionMode( False )
If Len( cFolder ) > 0 Then
oFilePickerDlg.setDisplayDirectory( ConvertToURL( cFolder ) )
EndIf
If Len( cFileName ) > 0 Then
oFilePickerDlg.setDefaultName( cFileName )
EndIf
' oFilePickerDlg.appendFilter( "OpenOffice.org Calc (SXC)", "sxc" )
' oFilePickerDlg.appendFilter( "Microsoft Excel (XLS)", "xls" )
' Change the Open button to say "Save".
' oFilePickerDlg.setLabel( com.sun.star.ui.dialogs.CommonFilePickerElementIds.PUSHBUTTON_OK, "Save" )
if oFilePickerDlg.execute() > 0 then
sFiles() = oFilePickerDlg.getFiles()
PickFileName= sFiles(0)
endif
End Function
|
Helpers, copied from other modules:
| Code: |
Function getURLPath(sURL$) as String
Dim structURL as new com.sun.star.util.URL
oSrv = createUnoService("com.sun.star.util.URLTransformer")
structURL.Complete = sURL
If oSrv.parseSmart(structURL,"Path") then
getURLPath = structURL.Protocol & structURL.Path
Endif
End Function
|
_________________ Rest in peace, oooforum.org
Get help on http://forum.openoffice.org |
|
| Back to top |
|
 |
JohnV Administrator

Joined: 07 Mar 2003 Posts: 8979 Location: Lexinton, Kentucky, USA
|
Posted: Fri Jul 21, 2006 10:21 am Post subject: |
|
|
Villeroy,
Well that was certainly a forthright answer and with code to boot. However, it still does not solve the problem, at least in Windows, of not being able to determine the path to a template stored in a normal directory if I just go there an open the template.
I have decided to solve my own problem with templates saved in related directories by following through on my thoughts in my second post above.
All my templates already start with a back quote character so they are available near the top of my various subdirectories and I have simply stored them as normal files instead of templates. ( I left the templates in my defined work directory alone.) The following macro is now tied to the Open Document event and if a file starting with a back quote is opened it simple does the equivalent of a Save As. | Code: | Sub TemplateSaveAs
Url = ThisComponent.getURL
If Len(URL) > 0 then
sp = Split(Url,"/")
filename = sp(uBound(sp))
If Left(filename,3) = "%60" then 'Represents a back quote in URL notation.
sp(uBound(sp)) = "" : path = Join(sp,"/")
sp = Split(Url,".") : ext = "." & sp(uBound(sp))
a$ = "Enter file name, without extension, below." & Chr(13)
a$ = a$ & Chr(13) & "You may also change the path."
b$ = "'Template' file detected. Preparing to Save As."
GetName:
Do
Url = ConvertToURL(InputBox(a$,b$,ConvertFromURL(path)))
If URL = "" then End
Loop While Url = path
Url = Url & ext
If FileExists(Url) then
c$ = "File exists. Overwrite?"
iAns = MsgBox(c$,3,"EXISTING FILE! " & ConvertFromURL(Url)
If iAns = 2 then End 'User clicked Cancel.
If iAns = 7 then Goto GetName 'User clicked No.
EndIf
Else End
EndIf
Else End
EndIf
ThisComponent.storeAsURL(Url,Array())
oFrame = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
dispatcher.executeDispatch(oFrame,".uno:UpdateInputFields","",0,Array())
dispatcher.executeDispatch(oFrame, ".uno:UpdateFields", "", 0, Array())
End Sub |
Initially I thought I would lose the queries for my User/Input fields but another recent post showed that could be triggered with Shift+Ctrl+F9 so I recorded that. I also use some Conditional Text fields that are dependant on the value of Input fields so I threw in the recording of the F9 key to update fields.
I have a few templates linked to a spreadsheet and I just tested one of those and it appears to work fine.
As far as I can tell the only loss is the ability to update styles in template child files but I have never used that anyway. If I ever needed it I could import the styles. |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|