Capturing Title in Writer Document Saved Filename.

Word will automatically use the first line of text in a document, generally the title, up to the first punctuation, such as a period or apostrophe, or carriage return as the suggested title of the documents filename when saving a document for the first time. Is it possible to do that in Writer?

I’m currently copying the title of a new document before clicking on Save for the first time, then pasting it into the filename box. It works just fine but it’s a bit annoying to have to do it every time I save a new document for the first time (yes, I’m lazy and spoiled by Word).

https://forum.openoffice.org/en/forum/viewtopic.php?f=21&t=20046&p=398042&hilit=First+line+filename#p398042
This should be at least a starting point for you. You may search for your interpunktion instead of taking a whole line of text. (The original code may also wrongly take an empty line if terminated with a hard line break while the paragraph continues.)

Thanks but, when I read that, my eyes glazed over, then crossed, and my toes curled. That was as solidly over my head as my roof.

Hello @LadyFitzgerald,

i think a better solution would be a macro that actually invokes the FilePicker dialog with your custom string as the Default File Name.

i’ll be working on such a macro in the coming time, please hold on.

You could then connect this macro to a newly created custom Menu item called “Save New …”, and attach a suitable keyboard shortcut such as CTRL+SHIFT+S to it.

Hello @LadyFitzgerald,

My apologies for the longer delay, i hope this matter is still of interest to you…

Here goes:

The method Writer_Save_New() is the one to be connected to a Keyboard Shortcut, a Button Command, and/or a Menu item Command, so that it can be invoked whenever you want to save a new Writer document.
If it is a New document, then the above procedure is performed; if it is not a New document, then the normal save procedure is performed.

A note about the dialog:

The “Save Dialog” implementation presented below in the function FileSaveDialog_Simple() has fewer features than the dialog that pops up when you choose “Save As…” in LibreOffice. For example it lacks the features of setting a Password, saving the current Selection Only, Editing Filter Options, etc.

However for the purpose of this question, it will suffice.

Steps to perform:

EDIT 1 ( 2018-01-25 )

  • updated the method Writer_SaveNew()

  • added stepwise instructions A) and B)

A) How to Copy-paste a Basic macro into your [My Macros & Dialogs].Standard Basic Library:

  1. Select all text in the code section below, and copy it to the Clipboard by pressing CTRL+C;
  2. In Writer, select the menu Tools : Macros : Edit Macros;
  3. In the Macro IDE Window that appears, in the “Object Catalog” on the left, doubleclick on the item called My Macros & Dialogs so that it expands;
  4. In the expanded section under “My Macros & Dialogs”, doubleclick on the item called Standard so that it expands;
  5. In the expanded section under “Standard”, doubleclick on any item so that it expands ( for example on the item called Module1 ); At the right side of the Macro IDE Window there should now appear all the text contents of the selected Module;
  6. Scroll down to the end of the Module, insert a few empty lines at the end by pressing the ENTER key, then paste all the copied text from the Clipboard by pressing CTRL+V.
  7. Save the Module by pressing CTRL+S.

B) How to Connect a macro to a Keyboard Shortcut:

  1. In Writer, select the menu Tools : Customize...;
  2. In the dialog that appears, select the tab Keyboard;
  3. In the “Shortcut Keys” listbox, scroll down to the Shortcut Key that you would like to use ( in this case i would recommend Shift+Ctrl+Alt+S ), and select it;
  4. In the “Category” listbox, scroll down to the item called LibreOffice Macros, and doubleclick on it so that it expands;
  5. In the expanded section under “LibreOffice Macros”, doubleclick on the item called My Macros so that it expands;
  6. In the expanded section under “My Macros”, doubleclick on the item called Standard so that it expands;
  7. In the expanded section under “Standard”, doubleclick on the Module that contains the methods added in step A), e.g. Module1;
  8. In the “Function” listbox, scroll down to the item called Writer_SaveNew(), and select it;
  9. Click the Modify button;
  10. Click the OK button.

Code:

Sub Writer_SaveNew()
REM See: https://ask.libreoffice.org/t/capturing-title-in-writer-document-saved-filename/27519
REM If the current Writer document is new, then this method will invoke the File Save dialog with the first
REM sentence from the current Writer Document as the suggested file name.
REM If this method is called when the current Writer document is not new, it will just save it without any dialog.
REM Requires additional methods:
REM 	Writer_getSentence()
REM 	cutStringAtMarks()
REM		FileSaveDialog_Simple()

	Dim oDoc As Object : oDoc = ThisComponent
	If Not oDoc.SupportsService( "com.sun.star.text.TextDocument" ) Then Exit Sub
	
	If oDoc.hasLocation() Then		REM the current document is not New:
		oDoc.store()				REM just save it immediately.
		
	Else	REM The current document is New: 
			REM open the Save File dialog with a custom file name.
		
REM	****  Set here the maximum length for the filename ( excluding the file extension ):		
		Const iMaxLength As Integer = 60		REM Set to 0 for No Maximum.

REM	****  Add here your desired punctuation marks to cut the filename at:
		Dim aPunctuation() : aPunctuation = Array( ":", ";", "," )

REM	****  Add here your characters to be removed from the filename:
		Dim aForbiddenChars() : aForbiddenChars = Array( "/", "\", "|", ":", """", "?", "*", "<", ">" )
		
		REM Get the 1st non-empty sentence...
		Dim strDefaultName As String
		strDefaultName	= Writer_getSentence( 1, oDoc )
		
		REM Cut the sentence at punctuation marks...
		strDefaultName	= cutStringAtMarks( strDefaultName, aPunctuation )
		
		REM Remove illegal characters...
		Dim i As Integer
		For i = 0 To 31								REM Remove all ASCII characters < 31...
			If Instr( strDefaultName, chr(i) ) > 0 Then strDefaultName = Join( Split( strDefaultName, chr(i) ), "" )
		Next i
		For i = 0 To uBound( aForbiddenChars )		REM Remove forbidden characters...
			If Instr( strDefaultName, aForbiddenChars(i) ) > 0 Then strDefaultName = Join( Split( strDefaultName, aForbiddenChars(i) ), "" )
		Next i
		
		REM Cut the resulting sentence at length...
		If iMaxLength > 0 Then strDefaultName = Left( strDefaultName, iMaxLength )
		
REM ****  NB. The resulting filename is still not guaranteed to be a valid filename.
REM ****  Yet it will be presented as initial filename in the following dialog:
		
		Dim aURL() : aURL = FileSaveDialog_Simple( oDoc, "TITLE", "", strDefaultName )
		If uBound( aURL ) > -1 Then oDoc.storeAsURL( aURL(0), Array() )
		
	End If
End Sub


Function cutStringAtMarks( sStringToCut As String, aCutMarks(), Optional bExclude ) As String
REM Returns the Left portion of <sStringToCut> up to the first encountered cutMark in the array <aCutMarks>.
REM <bExclude>	: Default=<True>=exclude the cutMark; Pass <False> to include it.
	If IsMissing( bExclude ) Then bExclude = True
	Dim i As Integer, lPos as Long, sCutMark As String
	Dim sString As String : sString = sStringToCut
	For i = 0 To uBound( aCutMarks )
		sCutMark	= aCutMarks( i )
		lPos		= InStr( 1, sString, sCutMark, 0 )
		If lPos > 0 Then
			If bExclude Then sString = Left( sString, lPos - 1 ) Else sString = Left( sString, lPos + Len( sCutMark ) - 1 )
		End If
	Next i
	cutStringAtMarks = sString
End Function


Function FileSaveDialog_Simple( oDoc As Object, Optional strTitle, Optional strDisplayDirectory, Optional strDefaultName, Optional aFilters(), Optional bRemote ) As Variant
REM Displays a FilePicker "Save As" dialog with optional Dialog Title, Initial Folder Path, Initial File Name, Export Filters, Remote Save Location,
REM <oDoc>			: The Document to be saved.
REM <strTitle>		: String to be shown in the dialog Title bar.
REM <strDisplayDirectory>: Path to a Folder whose contents will be shown when the dialog opens.
REM <strDefaultName>: String to be shown in the File Name Textbox when the dialog opens.
REM <aFilters>		: Array of com.sun.star.beans.StringPair describing the Export Filters to be included in the dialog.
REM					  These Filters should all have the EXPORT flag set.
REM					  Per StringPair: First = FilterName (e.g. "Jpeg Files"), Second = Extensions (e.g. "*.jpg").
REM <bRemote>		: Boolean indicating whether to display the Remote FilePicker for storing the file at a remote location, e.g. via FTP.
REM Returns: an Array containing the URL of the selected file, if the user has clicked on the Save button.
REM If the user has cancelled, this Function returns an Empty Array.
	
	If IsNull( oDoc ) Then Exit Function	REM No Document passed.
	
	REM First determine whether to use the Remote FilePicker, the System FilePicker, or the LibreOffice FilePicker.
	Dim aProps(1) As New com.sun.star.beans.PropertyValue
	aProps(0).Name	= "nodepath"
	aProps(0).Value	= "/org.openoffice.Office.Common/Misc/"
	aProps(1).Name	= "enableasync"
	aProps(1).Value	= False
	
	Dim oConfig As Object  : oConfig = createUnoService( "com.sun.star.configuration.ConfigurationProvider" )
	Dim oAccess As Object
	oAccess = oConfig.createInstanceWithArguments( "com.sun.star.configuration.ConfigurationAccess", aProps() )
	Dim bUseSystemDialogs As Boolean	REM Corresponds (inversely) to the setting in "Tools : Options : LibreOffice : General : Open/Save Dialogs : Use LibreOffice dialogs".
	bUseSystemDialogs = oAccess.UseSystemFileDialog

	Dim oFilePicker As Object
	If IsMissing( bRemote ) Then bRemote = False
	If bRemote Then
		oFilePicker = createUnoService( "com.sun.star.ui.dialogs.RemoteFilePicker" )
	Elseif bUseSystemDialogs Then
		oFilePicker = createUnoService( "com.sun.star.ui.dialogs.FilePicker" )
	Else
		oFilePicker = createUnoService( "com.sun.star.ui.dialogs.OfficeFilePicker" )
	End If
	
	REM Initialize the "Save As" Dialog with default UIMode = 10 ( auto extension ).
	Dim iUIMode As Integer :  iUIMode = 10
	oFilePicker.initialize( Array( iUIMode ) )
		
	If IsMissing( strTitle ) Then strTitle = "Save As:"
	oFilePicker.setTitle( strTitle )
	
	If Not IsMissing( strDisplayDirectory ) And FileExists( strDisplayDirectory ) Then
		oFilePicker.setDisplayDirectory( ConvertToURL( strDisplayDirectory ) )
	End If
	
	If Not IsMissing( strDefaultName ) Then oFilePicker.setDefaultName( strDefaultName )
	
	REM Append Export Filters.
	REM Default filter "All Formats" is added automatically in the System FilePicker (on Ubuntu 17.10);
	Const sFilterNameAllFormats = "All Formats"			REM Add it also in the LibreOffice FilePicker :
	If Not bRemote Or bUseSystemDialogs Then oFilePicker.appendFilter( sFilterNameAllFormats, "*.*" )
	If Not IsMissing( aFilters ) And IsArray( aFilters ) Then
		oFilePicker.appendFilterGroup( "Export Filters", aFilters )			REM Group Title is not shown.
	End If
	
	Dim iResult as Integer	:	iResult = oFilePicker.execute()				REM Execute the "Save As" Dialog.
	
	If iResult = com.sun.star.ui.dialogs.ExecutableDialogResults.OK Then	REM The User has clicked the Save button:
		REM At this stage the User has also clicked the Overwrite button if a file with the same name already exists.
		
		Dim aFiles() As String			:	aFiles = oFilePicker.getSelectedFiles()
		If uBound( aFiles ) > -1 Then		REM We have a URL ... Else something is wrong here.
			FileSaveDialog_Simple = aFiles() REM to save, call: oDoc.storeAsUrl( sURL, aSaveProps )
		End If
	Else		REM User Cancelled.
		FileSaveDialog_Simple = Array()
	End If
	oFilePicker.dispose
End Function

With Regards,
lib

Hello @LadyFitzgerald,

My apologies for the longer delay, i hope this matter is still of interest to you…

Here goes:

The method Writer_Save_New() is the one to be connected to a Keyboard Shortcut, a Button Command, and/or a Menu item Command, so that it can be invoked whenever you want to save a new Writer document.
If it is a New document, then the above procedure is performed; if it is not a New document, then the normal save procedure is performed.

A note about the dialog:

The “Save Dialog” implementation presented below in the function FileSaveDialog_Simple() has fewer features than the dialog that pops up when you choose “Save As…” in LibreOffice. For example it lacks the features of setting a Password, saving the current Selection Only, Editing Filter Options, etc.

However for the purpose of this question, it will suffice.

Steps to perform:

EDIT 1 ( 2018-01-25 )

  • updated the method Writer_SaveNew()

  • added stepwise instructions A) and B)

A) How to Copy-paste a Basic macro into your [My Macros & Dialogs].Standard Basic Library:

  1. Select all text in the code section below, and copy it to the Clipboard by pressing CTRL+C;
  2. In Writer, select the menu Tools : Macros : Edit Macros;
  3. In the Macro IDE Window that appears, in the “Object Catalog” on the left, doubleclick on the item called My Macros & Dialogs so that it expands;
  4. In the expanded section under “My Macros & Dialogs”, doubleclick on the item called Standard so that it expands;
  5. In the expanded section under “Standard”, doubleclick on any item so that it expands ( for example on the item called Module1 ); At the right side of the Macro IDE Window there should now appear all the text contents of the selected Module;
  6. Scroll down to the end of the Module, insert a few empty lines at the end by pressing the ENTER key, then paste all the copied text from the Clipboard by pressing CTRL+V.
  7. Save the Module by pressing CTRL+S.

B) How to Connect a macro to a Keyboard Shortcut:

  1. In Writer, select the menu Tools : Customize...;
  2. In the dialog that appears, select the tab Keyboard;
  3. In the “Shortcut Keys” listbox, scroll down to the Shortcut Key that you would like to use ( in this case i would recommend Shift+Ctrl+Alt+S ), and select it;
  4. In the “Category” listbox, scroll down to the item called LibreOffice Macros, and doubleclick on it so that it expands;
  5. In the expanded section under “LibreOffice Macros”, doubleclick on the item called My Macros so that it expands;
  6. In the expanded section under “My Macros”, doubleclick on the item called Standard so that it expands;
  7. In the expanded section under “Standard”, doubleclick on the Module that contains the methods added in step A), e.g. Module1;
  8. In the “Function” listbox, scroll down to the item called Writer_SaveNew(), and select it;
  9. Click the Modify button;
  10. Click the OK button.

Code:

Sub Writer_SaveNew()
REM See: https://ask.libreoffice.org/t/capturing-title-in-writer-document-saved-filename/27519
REM If the current Writer document is new, then this method will invoke the File Save dialog with the first
REM sentence from the current Writer Document as the suggested file name.
REM If this method is called when the current Writer document is not new, it will just save it without any dialog.
REM Requires additional methods:
REM 	Writer_getSentence()
REM 	cutStringAtMarks()
REM		FileSaveDialog_Simple()

	Dim oDoc As Object : oDoc = ThisComponent
	If Not oDoc.SupportsService( "com.sun.star.text.TextDocument" ) Then Exit Sub
	
	If oDoc.hasLocation() Then		REM the current document is not New:
		oDoc.store()				REM just save it immediately.
		
	Else	REM The current document is New: 
			REM open the Save File dialog with a custom file name.
		
REM	****  Set here the maximum length for the filename ( excluding the file extension ):		
		Const iMaxLength As Integer = 60		REM Set to 0 for No Maximum.

REM	****  Add here your desired punctuation marks to cut the filename at:
		Dim aPunctuation() : aPunctuation = Array( ":", ";", "," )

REM	****  Add here your characters to be removed from the filename:
		Dim aForbiddenChars() : aForbiddenChars = Array( "/", "\", "|", ":", """", "?", "*", "<", ">" )
		
		REM Get the 1st non-empty sentence...
		Dim strDefaultName As String
		strDefaultName	= Writer_getSentence( 1, oDoc )
		
		REM Cut the sentence at punctuation marks...
		strDefaultName	= cutStringAtMarks( strDefaultName, aPunctuation )
		
		REM Remove illegal characters...
		Dim i As Integer
		For i = 0 To 31								REM Remove all ASCII characters < 31...
			If Instr( strDefaultName, chr(i) ) > 0 Then strDefaultName = Join( Split( strDefaultName, chr(i) ), "" )
		Next i
		For i = 0 To uBound( aForbiddenChars )		REM Remove forbidden characters...
			If Instr( strDefaultName, aForbiddenChars(i) ) > 0 Then strDefaultName = Join( Split( strDefaultName, aForbiddenChars(i) ), "" )
		Next i
		
		REM Cut the resulting sentence at length...
		If iMaxLength > 0 Then strDefaultName = Left( strDefaultName, iMaxLength )
		
REM ****  NB. The resulting filename is still not guaranteed to be a valid filename.
REM ****  Yet it will be presented as initial filename in the following dialog:
		
		Dim aURL() : aURL = FileSaveDialog_Simple( oDoc, "TITLE", "", strDefaultName )
		If uBound( aURL ) > -1 Then oDoc.storeAsURL( aURL(0), Array() )
		
	End If
End Sub


Function cutStringAtMarks( sStringToCut As String, aCutMarks(), Optional bExclude ) As String
REM Returns the Left portion of <sStringToCut> up to the first encountered cutMark in the array <aCutMarks>.
REM <bExclude>	: Default=<True>=exclude the cutMark; Pass <False> to include it.
	If IsMissing( bExclude ) Then bExclude = True
	Dim i As Integer, lPos as Long, sCutMark As String
	Dim sString As String : sString = sStringToCut
	For i = 0 To uBound( aCutMarks )
		sCutMark	= aCutMarks( i )
		lPos		= InStr( 1, sString, sCutMark, 0 )
		If lPos > 0 Then
			If bExclude Then sString = Left( sString, lPos - 1 ) Else sString = Left( sString, lPos + Len( sCutMark ) - 1 )
		End If
	Next i
	cutStringAtMarks = sString
End Function


Function FileSaveDialog_Simple( oDoc As Object, Optional strTitle, Optional strDisplayDirectory, Optional strDefaultName, Optional aFilters(), Optional bRemote ) As Variant
REM Displays a FilePicker "Save As" dialog with optional Dialog Title, Initial Folder Path, Initial File Name, Export Filters, Remote Save Location,
REM <oDoc>			: The Document to be saved.
REM <strTitle>		: String to be shown in the dialog Title bar.
REM <strDisplayDirectory>: Path to a Folder whose contents will be shown when the dialog opens.
REM <strDefaultName>: String to be shown in the File Name Textbox when the dialog opens.
REM <aFilters>		: Array of com.sun.star.beans.StringPair describing the Export Filters to be included in the dialog.
REM					  These Filters should all have the EXPORT flag set.
REM					  Per StringPair: First = FilterName (e.g. "Jpeg Files"), Second = Extensions (e.g. "*.jpg").
REM <bRemote>		: Boolean indicating whether to display the Remote FilePicker for storing the file at a remote location, e.g. via FTP.
REM Returns: an Array containing the URL of the selected file, if the user has clicked on the Save button.
REM If the user has cancelled, this Function returns an Empty Array.
	
	If IsNull( oDoc ) Then Exit Function	REM No Document passed.
	
	REM First determine whether to use the Remote FilePicker, the System FilePicker, or the LibreOffice FilePicker.
	Dim aProps(1) As New com.sun.star.beans.PropertyValue
	aProps(0).Name	= "nodepath"
	aProps(0).Value	= "/org.openoffice.Office.Common/Misc/"
	aProps(1).Name	= "enableasync"
	aProps(1).Value	= False
	
	Dim oConfig As Object  : oConfig = createUnoService( "com.sun.star.configuration.ConfigurationProvider" )
	Dim oAccess As Object
	oAccess = oConfig.createInstanceWithArguments( "com.sun.star.configuration.ConfigurationAccess", aProps() )
	Dim bUseSystemDialogs As Boolean	REM Corresponds (inversely) to the setting in "Tools : Options : LibreOffice : General : Open/Save Dialogs : Use LibreOffice dialogs".
	bUseSystemDialogs = oAccess.UseSystemFileDialog

	Dim oFilePicker As Object
	If IsMissing( bRemote ) Then bRemote = False
	If bRemote Then
		oFilePicker = createUnoService( "com.sun.star.ui.dialogs.RemoteFilePicker" )
	Elseif bUseSystemDialogs Then
		oFilePicker = createUnoService( "com.sun.star.ui.dialogs.FilePicker" )
	Else
		oFilePicker = createUnoService( "com.sun.star.ui.dialogs.OfficeFilePicker" )
	End If
	
	REM Initialize the "Save As" Dialog with default UIMode = 10 ( auto extension ).
	Dim iUIMode As Integer :  iUIMode = 10
	oFilePicker.initialize( Array( iUIMode ) )
		
	If IsMissing( strTitle ) Then strTitle = "Save As:"
	oFilePicker.setTitle( strTitle )
	
	If Not IsMissing( strDisplayDirectory ) And FileExists( strDisplayDirectory ) Then
		oFilePicker.setDisplayDirectory( ConvertToURL( strDisplayDirectory ) )
	End If
	
	If Not IsMissing( strDefaultName ) Then oFilePicker.setDefaultName( strDefaultName )
	
	REM Append Export Filters.
	REM Default filter "All Formats" is added automatically in the System FilePicker (on Ubuntu 17.10);
	Const sFilterNameAllFormats = "All Formats"			REM Add it also in the LibreOffice FilePicker :
	If Not bRemote Or bUseSystemDialogs Then oFilePicker.appendFilter( sFilterNameAllFormats, "*.*" )
	If Not IsMissing( aFilters ) And IsArray( aFilters ) Then
		oFilePicker.appendFilterGroup( "Export Filters", aFilters )			REM Group Title is not shown.
	End If
	
	Dim iResult as Integer	:	iResult = oFilePicker.execute()				REM Execute the "Save As" Dialog.
	
	If iResult = com.sun.star.ui.dialogs.ExecutableDialogResults.OK Then	REM The User has clicked the Save button:
		REM At this stage the User has also clicked the Overwrite button if a file with the same name already exists.
		
		Dim aFiles() As String			:	aFiles = oFilePicker.getSelectedFiles()
		If uBound( aFiles ) > -1 Then		REM We have a URL ... Else something is wrong here.
			FileSaveDialog_Simple = aFiles() REM to save, call: oDoc.storeAsUrl( sURL, aSaveProps )
		End If
	Else		REM User Cancelled.
		FileSaveDialog_Simple = Array()
	End If
	oFilePicker.dispose
End Function

With Regards,
lib

I’m sorry but I still have no idea what is being talked about. Where and what is this Standard Basic Library? Step #2 was gibberish to me.

I need simple, detailed, step by step instructions. Don’t assume I know anything.

Though the questions “How to copy-paste a macro into my Basic Macro Library?” and “How to connect a Shortcut Key to a macro?” might already have been answered in a better way elsewhere on the AskLibreOffice forum, i have included a stepwise instruction for both these tasks in my Original Answer ( under EDIT 1 ).

Hi, librebel. I get an error when I use you macro. It says: “BASIC runtime error.
Sub-procedure or function procedure not defined,” then the code “strDefaultName = Writer_getSentence( 1, oDoc )” is highlighted. Did I do something wrong?

Also would it be possible, using your macro, to get the title from an input field?

Thank you.