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 section is not for asking questions about writing your own macros.
Here is what I tweaked, knowing that I don't need the timestamp (thus, the code for that was removed):
- The SaveLastEditPosition part will delete the previous bookmark and create a new one that should appear quite at the top of the bookmarks list in the Navigator. It will be: - Last Edit Position - XXX with XXX being the initials of the user (from his AOO/LO profile).
- A GotoCurrenttypistLastPositionBookmark routine has been added. Should be assigned to a toolbar button or a shortcut to bring you at the current user bookmark (if any).
Edit: Updated code in later post below.
LibreOffice 24.8 on Xubuntu 24.10 and 24.8 portable on Windows 10
I was working on a bookmarks extension a long while ago which I never finished - with the idea of using the zero width space character (&H200B) to mark the bookmark - the start or both ends if a range. That character appears as a grey line which is visible or shown depending on whether view field shadings is set. Being zero width it doesn't alter the layout of the document. A possible suggestion for this perhaps?
Edit: there may of course be some special reason for it appearing as a field like line and should not be entered as a character in the document - I wouldn't know.
Windows 10, Openoffice 4.1.11, LibreOffice 7.4.0.3 (x64)
I have disabled the display of the bookmarks because when there is a ToC with links to the headings, all those headings get that gray thin line as the first character of the heading. I couldn't stand that. in LO, it is in Options > Tools > Writer > Formatting Aids.
LibreOffice 24.8 on Xubuntu 24.10 and 24.8 portable on Windows 10
An alternative way of adding the author/time information that I was looking at before (and possibly other information such as a note or a color for color coding [Edit: or a category]) is instead of including it in the name to add it to a parallel custom document property identified by the same name.
That information wouldn't then be visible in the navigator list of bookmarks but could be included or excluded from a list of bookmarks in your own custom dialog.
(I get a lot of these ideas and projects snowball which is why some get abandoned without completion...)
Edit 2: There's a flaw in OO's (but not LO's) navigator list of bookmarks - they aren't in document order. But the list of bookmark names provided for macros is and can - with one line of code - be added to a dialog listbox. Much more could be made of bookmarks in both...
Windows 10, Openoffice 4.1.11, LibreOffice 7.4.0.3 (x64)
Updated code in case the selection happens to be a picture. Note: doesn't work if the pic is anchored to page. Thus, error handler kept in case of error (just exit the routine). Thanks to FJCC and JeJe here.
Private sIdentifier as String
'***************************
'* Save last edit position *
'***************************
Sub SaveLastEditPosition()
REM Very raw, skipping the additional functionality I made the code for:
REM Distinguishing "last position" per user. Also implementable "per author"
REM if a respective UDP is defined under the name "currenttypist".
REM Currently pEventInfo isn't evaluated. You may change that if you want to
REM modify the action dending on what mofiers wer used with a toolbar area
REM or any info provided by a FormControl used for the call.
Dim oVC as Object, oDoc as Object, oAnchor as Object
oVC = ThisComponent.currentController.ViewCursor
sIdentifier = "- Last Edit Position - " ' Also in the GotoCurrenttypistLastPositionBookmark routine
oDoc = ThisComponent
If NOT oDoc.supportsService("com.sun.star.text.TextDocument") Then Exit Sub
REM hard-coded names
Const useAsID = "currenttypist"
Const useAsIDalt = "initials" REM "alt" for alternative. From the following node:
Const dataNode = "/org.openoffice.UserProfile/Data"
REM Assumed preferences
Const bookmarkStart = False
If oDoc.CurrentController.Selection.supportsService("com.sun.star.text.TextGraphicObject") then
If oDoc.CurrentController.Selection.AnchorType =com.sun.star.text.TextContentAnchorType.AT_PAGE then
oDoc.CurrentController.viewcursor.jumptopage (oDoc.CurrentController.Selection.AnchorPageNo, false)
Else
oAnchor = oDoc.CurrentController.Selection.Anchor
oDoc.CurrentController.select(oAnchor)
End If
End If
insPos = oVC.collapseToEnd
newBmN = tryGetPropertyValue(oDoc.DocumentProperties.UserDefinedProperties, UseAsID, "")'.getPropertyValue("author")
If newBmN = "" Then newBmN = simplePropertyValueFromRegistryModificationsXcu(dataNode, useAsIDalt)
newBmN = sIdentifier & newBmN
removePreviousBookmarks(oDoc, newBmN)
newBm = ThisComponent.createInstance("com.sun.star.text.Bookmark")
newBm.Name = newBmN
insCur = oVC.text.createTextCursorByRange(oVC)
oVC.text.insertTextContent(insCur, newBm, False)
End Sub
' Thanks to Andrew Pitonyak I could easily code this needed helper:
Function simplePropertyValueFromRegistryModificationsXcu(pNodePath As String, pPropertyName As String) As Variant
simplePropertyValueFromRegistryModificationsXcu = ":err:"
On Local Error Goto fail
Dim structNode, providerSrv
Dim arguments(0) As New com.sun.star.beans.PropertyValue
Const providerSrvN = "com.sun.star.configuration.ConfigurationProvider"
Const structNodeN = "com.sun.star.configuration.ConfigurationAccess"
providerSrv = createUnoService(providerSrvN)
arguments(0).Name = "nodepath"
arguments(0).Value = pNodePath
structNode = providerSrv.createInstanceWithArguments(structNodeN, arguments())
simplePropertyValueFromRegistryModificationsXcu = structNode.getPropertyValue(pPropertyName)
fail:
End Function
Function tryGetPropertyValue(pPropertyBag, pPropertyName, pDefault)
tryGetPropertyValue = pDefault
On Local Error Goto fail
tryGetPropertyValue = pPropertyBag.getPropertyValue(pPropertyName)
fail:
End Function
'************************************
'* Remove previous bookmark *
'************************************
Sub removePreviousBookmarks(oDoc, sUserIdentifier as string)
bms = oDoc.Bookmarks
ub = bms.count - 1
For b = ub To 0 Step -1
bm = bms(b)
bmN = bm.Name
If bmN<>sUserIdentifier Then Goto nextBm
oDoc.Text.removeTextContent(bm)
nextBm:
Next b
End Sub
'*********************************
'* Retrieve last edit position *
'*********************************
Sub GotoCurrenttypistLastPositionBookmark()
oDoc = ThisComponent
If NOT oDoc.supportsService("com.sun.star.text.TextDocument") Then Exit Sub
REM hard-coded names
Const useAsID = "currenttypist"
Const useAsIDalt = "initials" REM "alt" for alternative. From the following node:
Const dataNode = "/org.openoffice.UserProfile/Data"
REM Assumed preferences
sIdentifier = "- Last Edit Position - "
refBmN = tryGetPropertyValue(oDoc.DocumentProperties.UserDefinedProperties, UseAsID, "")'.getPropertyValue("author")
If refBmN="" Then refBmN = simplePropertyValueFromRegistryModificationsXcu(dataNode, useAsIDalt)
refBmN = sIdentifier & refBmN
bms = oDoc.Bookmarks
ub = bms.count - 1
For b = ub To 0 Step -1
bm = bms(b)
bmN = bm.Name
If bmN<>refBmN Then Goto nextBm
ViewCursor = oDoc.CurrentController.getviewCursor()
bmPos = oDoc.Bookmarks.getByName(bmN).Anchor
ViewCursor.gotorange(bmPos, False)
nextBm:
Next b
End Sub
LibreOffice 24.8 on Xubuntu 24.10 and 24.8 portable on Windows 10
Hi, Hagar.
I don't actually work very much with bookmarks, and you will know better than I do that there are lots of "CurrentSelection" cases you can't create a bookmark for. In case of a multiple selection of TextRange the feature is supported by the UI, but the bookmark doesn't memorize all the ranges but just one specific position. No bookmarking at all can be done via the UI if GraphicObject or Shape is selected. In these cases you can easily resort to the .Anchor property when doing it by UserCode. (I never anchored something "ToPage").
The final nightmare, however are TextTable Objects. And not just Lupp, but also the UI are on strike concerning bookmarks insofar. It may seem as if TextTable implementation never was considered seriously in advance - and then it was too late. As long as your selection is from text inside the table everything works as expected, but as soon as complete cells are selected (always a contiguous cell range then) it's getting a nightmare. The selection is a TextTableCursor object (service) now, and that's the DAS (DumbestAssumableService). It neither knows (tells) the table it is belonging to nor anything else of use. The only usable method in our context is the 'gotoCellByName(name, absorb)', and since we are clever, we also find the property .RangeName from which we "easily" get the first cell by Split(.RangeName, ":")(0). Now the miracle: If we use the CurrentController to select the TextTableCursor after that "goto", the new CurrentSelection isn't a cursor with exactly one cell, but the first text position inside the cell. and this text now knows to what table it belongs. Hail! In fact such gimmick is the only way I know how to get the table to which a selected cellrange belongs by code.
You see: There were reasons for which I preferred to not include "nightmare selections" with my code for automated bookmarking.
On Windows 10: LibreOffice 24.8.3 and older versions, PortableOpenOffice 4.1.7 and older, StarOffice 5.2
---
Lupp from München
Indeed.
But the methods provided seem to cover most of the usual cases. I've not checked with more advanced features like form fields for example.
I stumbled upon the pic issue because it's pretty frequent that I close my file when the last thing selected is a picture. This this nightmare selection was worth tackling for my use.
Up to a future user to improve the code further if there is another nightmare selection that bother him.
LibreOffice 24.8 on Xubuntu 24.10 and 24.8 portable on Windows 10