SuperbChemistry 3.0
[superbchemistry/superbchemistry.git] / extension / SuperbChemistry / Main.xba
... / ...
CommitLineData
1<?xml version="1.0" encoding="UTF-8"?>
2<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
3<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Main" script:language="StarBasic">Option Explicit
4
5Function HaveSelection(doc As Object)
6 Dim sel as Object
7 sel = doc.CurrentController.Selection
8 If sel.Count &gt; 1 Then
9 HaveSelection = True
10 Exit Function
11 End If
12 Dim s0
13 s0 = sel.getByIndex(0)
14 If s0.Text.compareRegionStarts(s0.Start, s0.End) = 0 Then
15 HaveSelection = False
16 Else
17 HaveSelection = True
18 End If
19End Function
20
21&apos; Regular expression replace in the document, creating superscripts if
22&apos; superb &gt; 0 or subscripts if superb &lt; 0.
23Sub SuperbReplace(doc As Object, searchRegex As String, replacePattern As String, superb As Integer)
24
25 Dim rd As Object
26 rd = doc.createReplaceDescriptor()
27
28 rd.SearchCaseSensitive = true
29 rd.SearchRegularExpression = true
30 rd.setSearchString(searchRegex)
31 rd.setReplaceString(replacePattern)
32
33 If superb &lt;&gt; 0 Then
34 Dim replaceAttrs(1) As New com.sun.star.beans.PropertyValue
35 replaceAttrs(0).Name = &quot;CharEscapement&quot;
36 If superb &gt; 0 Then
37 replaceAttrs(0).Value = 33
38 Else
39 &apos; The default escapement for subscripts is -33, which looked bad to me in
40 &apos; chemical formulas. This looks better. Modify to your taste.
41 replaceAttrs(0).Value = -9
42 End If
43 replaceAttrs(1).Name = &quot;CharEscapementHeight&quot;
44 replaceAttrs(1).Value = 58
45 rd.setReplaceAttributes(replaceAttrs)
46 End If
47
48 doc.replaceAll(rd)
49
50End Sub
51
52Sub ReplaceInSelection(doc As Object, searchRegex As String, replacePattern As String)
53
54 Dim frame As Object, dispatcher As Object
55 frame = doc.CurrentController.Frame
56 dispatcher = createUnoService(&quot;com.sun.star.frame.DispatchHelper&quot;)
57
58 Dim args(6) As New com.sun.star.beans.PropertyValue
59 args(0).Name = &quot;SearchItem.AlgorithmType&quot;
60 args(0).Value = 1
61 args(1).Name = &quot;SearchItem.SearchFlags&quot;
62 args(1).Value = &amp;H1800 &apos; Search in selection
63 args(2).Name = &quot;SearchItem.SearchString&quot;
64 args(2).Value = searchRegex
65 args(3).Name = &quot;SearchItem.ReplaceString&quot;
66 args(3).Value = replacePattern
67 args(4).Name = &quot;SearchItem.Command&quot;
68 args(4).Value = 3
69 args(5).Name = &quot;SearchItem.AlgorithmType2&quot;
70 args(5).Value = 2
71 args(6).Name = &quot;Quiet&quot;
72 args(6).Value = true
73
74 dispatcher.executeDispatch(frame, &quot;.uno:ExecuteSearch&quot;, &quot;&quot;, 0, args())
75
76End Sub
77
78Global formatSelectionWarningShown As Boolean
79&apos; I haven&apos;t found a way to initialize the variable, but it looks like its
80&apos; default value is treated as false in an if statement.
81&apos;formatSelectionWarningShown = False
82
83Sub FormatSelectionOrDocumentDebug()
84 &apos; Replacing with an empty replacement string triggers a bug in LibreOffice
85 &apos; (https://bugs.documentfoundation.org/show_bug.cgi?id=136577), so we must
86 &apos; avoid it. Fortunately, avoiding it is pretty straightforward.
87
88 &apos; Insert @m@ between an item and a number or charge.
89 If HaveSelection(ThisComponent) Then
90 &apos; doc.replaceAll is not capable of searching a selection, while the
91 &apos; dispatch-based replace API uses the current format options in the
92 &apos; &quot;Find &amp; Replace&quot; dialog and does not let us change them, which means that
93 &apos; (1) existing settings can break things and (2) we cannot make superscripts
94 &apos; and subscripts. We do the best we can by using one dispatch-based replace
95 &apos; to tag all the sequences we want to operate on (which loses the selection in
96 &apos; OpenOffice anyway) and then proceed with replaceAll calls on the whole
97 &apos; document, which will only operate on the already tagged sequences.
98 If Not formatSelectionWarningShown Then
99 MsgBox &quot;Due to limitations in the OpenOffice/LibreOffice API, the &quot; &amp; _
100 &quot;&quot;&quot;Format selection&quot;&quot; command may not process some chemical formulas &quot; &amp; _
101 &quot;in the selection or may apply incorrect formatting if any format &quot; &amp; _
102 &quot;options are active in the &quot;&quot;Find &amp; Replace&quot;&quot; dialog box. If this &quot; &amp; _
103 &quot;happens, just undo the command (if any changes were made), clear the &quot; &amp; _
104 &quot;format options in the &quot;&quot;Find &amp; Replace&quot;&quot; dialog box (focus the &quot; &amp; _
105 &quot;&quot;&quot;Find&quot;&quot; field, click &quot;&quot;No Format&quot;&quot;, and repeat for the &quot;&quot;Replace&quot;&quot; &quot; &amp; _
106 &quot;field), and run &quot;&quot;Format selection&quot;&quot; again.&quot; &amp; Chr$(13) &amp; Chr$(13) &amp; _
107 &quot;This message is always shown on the first &quot;&quot;Format selection&quot;&quot; &quot; &amp; _
108 &quot;command in each OpenOffice/LibreOffice session because &quot; &amp; _
109 &quot;SuperbChemistry has no way to detect whether format options are &quot; &amp; _
110 &quot;active in &quot;&quot;Find &amp; Replace&quot;&quot;.&quot;, _
111 0, &quot;SuperbChemistry &quot;&quot;Format selection&quot;&quot; notice&quot;
112 formatSelectionWarningShown = True
113 End If
114 ReplaceInSelection(ThisComponent, &quot;(?&lt;=[A-Z][a-z]?|[\])}])[-+−0-9]+&quot;, &quot;@m@&amp;&quot;)
115 Else
116 SuperbReplace(ThisComponent, &quot;(?&lt;=[A-Z][a-z]?|[\])}])[-+−0-9]+&quot;, &quot;@m@&amp;&quot;, 0)
117 End If
118
119 &apos; Insert @c@ after a charge.
120 SuperbReplace(ThisComponent, &quot;(?&lt;=@m@)([0-9]*[-+−])(?=[ \t\])}.,:;?!&apos;&quot;&quot;]|$)&quot;, &quot;&amp;@c@&quot;, 0)
121
122 &apos; Real minus signs in charges.
123 SuperbReplace(ThisComponent, &quot;-@c@&quot;, &quot;−@c@&quot;, 0)
124
125 &apos; Some groups grab a single following digit as a quantity rather than a charge amount.
126 &apos; Insert @sq@ marker to prevent the charge from grabbing the digit.
127 SuperbReplace(ThisComponent, &quot;(?&lt;=(H|O|F|Cl|Br|I|[\])}])@m@)[0-9]&quot;, &quot;&amp;@sq@&quot;, 0)
128
129 &apos; Each charge grabs at most one digit and moves the @c@ in front to prevent the
130 &apos; quantity from grabbing the digit.
131 SuperbReplace(ThisComponent, &quot;([0-9]?[−+])@c@&quot;, &quot;@c@$1&quot;, 1)
132
133 &apos; Remove any @sq@ markers so items can grab all the digits that follow for the quantity.
134 SuperbReplace(ThisComponent, &quot;(.)@sq@&quot;, &quot;$1&quot;, 0)
135
136 &apos; At this point, we have only @m@ and @c@ markers left.
137
138 &apos; Format quantities: as many digits as we can still grab.
139 &apos; We have to allow @ as a following character for our own @c@ tag.
140 SuperbReplace(ThisComponent, &quot;(?&lt;=@m@)[0-9]+(?=[@A-Z \t\])}.,:;?!&apos;&quot;&quot;]|$)&quot;, &quot;&amp;&quot;, -1)
141
142 &apos; Clean up @c@ markers. We know there is a charge sign after each.
143 SuperbReplace(ThisComponent, &quot;@c@(.)&quot;, &quot;$1&quot;, 0)
144
145 &apos; Clean up @m@ markers. We know there is some character before each.
146 SuperbReplace(ThisComponent, &quot;(.)@m@&quot;, &quot;$1&quot;, 0)
147
148End Sub
149
150Dim madeChanges As Boolean
151
152Sub UndoListener_undoActionAdded()
153End Sub
154Sub UndoListener_actionUndone()
155End Sub
156Sub UndoListener_actionRedone()
157End Sub
158Sub UndoListener_allActionsCleared()
159End Sub
160Sub UndoListener_redoActionsCleared()
161End Sub
162Sub UndoListener_resetAll()
163End Sub
164Sub UndoListener_enteredContext()
165End Sub
166Sub UndoListener_enteredHiddenContext()
167End Sub
168Sub UndoListener_leftContext()
169 madeChanges = True
170End Sub
171Sub UndoListener_leftHiddenContext()
172End Sub
173Sub UndoListener_cancelledContext()
174End Sub
175
176Sub FormatSelectionOrDocument()
177
178 Dim undoActionName As String
179 If HaveSelection(ThisComponent) Then
180 undoActionName = &quot;SuperbChemistry: Format selection&quot;
181 Else
182 undoActionName = &quot;SuperbChemistry: Format document&quot;
183 End If
184 ThisComponent.UndoManager.enterUndoContext(undoActionName)
185
186 On Error Goto ErrorHandler
187 FormatSelectionOrDocumentDebug
188 On Error Goto 0
189
190 ThisComponent.UndoManager.leaveUndoContext()
191 Exit Sub
192
193ErrorHandler:
194
195 &apos; If our undo context is nonempty, we want to undo the generated action.
196 &apos; If not, we do not want to undo as that would undo the user&apos;s previous
197 &apos; action. If we just check whether the title of the last undoable action
198 &apos; is &quot;SuperbChemistry: Format (selection|document)&quot;, that might be wrong if
199 &apos; the user ran FormatDocument twice in a row: probably unlikely, but the
200 &apos; completely correct check is not that hard.
201 Dim listener As Object
202 listener = CreateUnoListener(&quot;UndoListener_&quot;, &quot;com.sun.star.document.XUndoManagerListener&quot;)
203 madeChanges = False
204 ThisComponent.UndoManager.addUndoManagerListener(listener)
205 ThisComponent.UndoManager.leaveUndoContext()
206 ThisComponent.UndoManager.removeUndoManagerListener(listener)
207 If madeChanges Then
208 ThisComponent.UndoManager.undo()
209 ThisComponent.UndoManager.clearRedo()
210 End If
211
212 MsgBox &quot;SuperbChemistry encountered an unexpected error:&quot; &amp; Chr$(13) &amp; Chr$(13) &amp; _
213 &quot;Code &quot; &amp; Err &amp; &quot;: &quot; &amp; Error$ &amp; Chr$(13) &amp; Chr$(13) &amp; _
214 &quot;Any changes made so far have been undone.&quot; &amp; Chr$(13) &amp; Chr$(13) &amp; _
215 &quot;SuperbChemistry needed to catch the error in order to leave your undo &quot; &amp; _
216 &quot;history in a consistent state. If the problem is reproducible and you &quot; &amp; _
217 &quot;want to see the precise error location, run the FormatDocumentOrSelectionDebug &quot; &amp; _
218 &quot;macro, but be advised that it may generate multiple entries in the undo &quot; &amp; _
219 &quot;history and will not undo them on error.&quot;, _
220 0, &quot;SuperbChemistry internal error&quot;
221 On Error Goto 0
222End Sub
223
224</script:module>