1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 /**
21  * AccEditableText.cpp : Implementation of CUAccCOMApp and DLL registration.
22  */
23 #include "stdafx.h"
24 #include "AccEditableText.h"
25 
26 #if defined __clang__
27 #pragma clang diagnostic push
28 #pragma clang diagnostic ignored "-Wnon-virtual-dtor"
29 #endif
30 #include  <UAccCOM.h>
31 #if defined __clang__
32 #pragma clang diagnostic pop
33 #endif
34 
35 #include <vcl/svapp.hxx>
36 #include <o3tl/char16_t2wchar_t.hxx>
37 
38 #include <com/sun/star/accessibility/XAccessible.hpp>
39 #include <com/sun/star/accessibility/XAccessibleContext.hpp>
40 #include <com/sun/star/accessibility/XAccessibleText.hpp>
41 #include <com/sun/star/awt/FontSlant.hpp>
42 #include <com/sun/star/beans/PropertyValue.hpp>
43 #include <com/sun/star/style/LineSpacing.hpp>
44 #include <com/sun/star/style/TabStop.hpp>
45 #include <vector>
46 
47 using namespace com::sun::star::accessibility;
48 using namespace com::sun::star::uno;
49 using namespace com::sun::star::awt;
50 using namespace com::sun::star::beans;
51 using namespace std;
52 
53 /**
54  * Copy a range of text to the clipboard.
55  *
56  * @param    startOffset    the start offset of copying.
57  * @param    endOffset      the end offset of copying.
58  * @param    success        the boolean result to be returned.
59  */
copyText(long startOffset,long endOffset)60 COM_DECLSPEC_NOTHROW STDMETHODIMP CAccEditableText::copyText(long startOffset, long endOffset)
61 {
62     SolarMutexGuard g;
63 
64     ENTER_PROTECTED_BLOCK
65 
66     // #CHECK XInterface#
67     if(!pRXEdtTxt.is())
68     {
69         return E_FAIL;
70     }
71 
72     if ( GetXInterface()->copyText( startOffset, endOffset ) )
73         return S_OK;
74 
75     return E_FAIL;
76 
77     LEAVE_PROTECTED_BLOCK
78 }
79 
80 /**
81  * Deletes a range of text.
82  *
83  * @param    startOffset    the start offset of deleting.
84  * @param    endOffset      the end offset of deleting.
85  * @param    success        the boolean result to be returned.
86  */
deleteText(long startOffset,long endOffset)87 COM_DECLSPEC_NOTHROW STDMETHODIMP CAccEditableText::deleteText(long startOffset, long endOffset)
88 {
89     SolarMutexGuard g;
90 
91     ENTER_PROTECTED_BLOCK
92 
93     if( !pRXEdtTxt.is() )
94         return E_FAIL;
95 
96     if( GetXInterface()->deleteText( startOffset, endOffset ) )
97         return S_OK;
98 
99     return E_FAIL;
100 
101     LEAVE_PROTECTED_BLOCK
102 }
103 
104 /**
105  * Inserts text at a specified offset.
106  *
107  * @param    offset    the offset of inserting.
108  * @param    text      the text to be inserted.
109  * @param    success   the boolean result to be returned.
110  */
insertText(long offset,BSTR * text)111 COM_DECLSPEC_NOTHROW STDMETHODIMP CAccEditableText::insertText(long offset, BSTR * text)
112 {
113     SolarMutexGuard g;
114 
115     ENTER_PROTECTED_BLOCK
116 
117     if (text == nullptr)
118         return E_INVALIDARG;
119 
120     if( !pRXEdtTxt.is() )
121         return E_FAIL;
122 
123     OUString ouStr(o3tl::toU(*text));
124 
125     if( GetXInterface()->insertText( ouStr, offset ) )
126         return S_OK;
127 
128     return E_FAIL;
129 
130     LEAVE_PROTECTED_BLOCK
131 }
132 
133 /**
134  * Cuts a range of text to the clipboard.
135  *
136  * @param    startOffset    the start offset of cutting.
137  * @param    endOffset      the end offset of cutting.
138  * @param    success        the boolean result to be returned.
139  */
cutText(long startOffset,long endOffset)140 COM_DECLSPEC_NOTHROW STDMETHODIMP CAccEditableText::cutText(long startOffset, long endOffset)
141 {
142     SolarMutexGuard g;
143 
144     ENTER_PROTECTED_BLOCK
145 
146     if( !pRXEdtTxt.is() )
147         return E_FAIL;
148 
149     if( GetXInterface()->cutText( startOffset, endOffset ) )
150         return S_OK;
151 
152     return E_FAIL;
153 
154     LEAVE_PROTECTED_BLOCK
155 }
156 
157 /**
158  * Pastes text from clipboard at specified offset.
159  *
160  * @param    offset    the offset of pasting.
161  * @param    success   the boolean result to be returned.
162  */
pasteText(long offset)163 COM_DECLSPEC_NOTHROW STDMETHODIMP CAccEditableText::pasteText(long offset)
164 {
165     SolarMutexGuard g;
166 
167     ENTER_PROTECTED_BLOCK
168 
169     if( !pRXEdtTxt.is() )
170         return E_FAIL;
171 
172     if( GetXInterface()->pasteText( offset ) )
173         return S_OK;
174 
175     return E_FAIL;
176 
177     LEAVE_PROTECTED_BLOCK
178 }
179 
180 /**
181  * Replaces range of text with new text.
182  *
183  * @param    startOffset    the start offset of replacing.
184  * @param    endOffset      the end offset of replacing.
185  * @param    text           the replacing text.
186  * @param    success        the boolean result to be returned.
187  */
replaceText(long startOffset,long endOffset,BSTR * text)188 COM_DECLSPEC_NOTHROW STDMETHODIMP CAccEditableText::replaceText(long startOffset, long endOffset, BSTR * text)
189 {
190     SolarMutexGuard g;
191 
192     ENTER_PROTECTED_BLOCK
193 
194     // #CHECK#
195     if (text == nullptr)
196         return E_INVALIDARG;
197     if( !pRXEdtTxt.is() )
198         return E_FAIL;
199 
200     OUString ouStr(o3tl::toU(*text));
201 
202     if( GetXInterface()->replaceText( startOffset,endOffset, ouStr) )
203         return S_OK;
204     return E_FAIL;
205 
206     LEAVE_PROTECTED_BLOCK
207 }
208 
209 /**
210  * Sets attributes of range of text.
211  *
212  * @param    startOffset    the start offset.
213  * @param    endOffset      the end offset.
214  * @param    attributes     the attribute text.
215  * @param    success        the boolean result to be returned.
216  */
setAttributes(long startOffset,long endOffset,BSTR * attributes)217 COM_DECLSPEC_NOTHROW STDMETHODIMP CAccEditableText::setAttributes(long startOffset, long endOffset, BSTR * attributes)
218 {
219     SolarMutexGuard g;
220 
221     ENTER_PROTECTED_BLOCK
222 
223     // #CHECK#
224     if (attributes == nullptr)
225         return E_INVALIDARG;
226     if( !pRXEdtTxt.is() )
227         return E_FAIL;
228 
229     OUString ouStr(o3tl::toU(*attributes));
230 
231     vector< OUString > vecAttr;
232     for (sal_Int32 nIndex {0}; nIndex >= 0; )
233         vecAttr.push_back(ouStr.getToken(0, ';', nIndex));
234 
235     Sequence< PropertyValue > beanSeq(vecAttr.size());
236     for(std::vector<OUString>::size_type i = 0; i < vecAttr.size(); i ++)
237     {
238         OUString attr = vecAttr[i];
239         sal_Int32 nPos = attr.indexOf(':');
240         if(nPos > -1)
241         {
242             OUString attrName = attr.copy(0, nPos);
243             OUString attrValue = attr.copy(nPos + 1);
244             beanSeq[i].Name = attrName;
245             get_AnyFromOLECHAR(attrName, attrValue, beanSeq[i].Value);
246         }
247     }
248 
249     if( GetXInterface()->setAttributes( startOffset,endOffset, beanSeq) )
250         return S_OK;
251 
252     return E_FAIL;
253 
254     LEAVE_PROTECTED_BLOCK
255 }
256 
257 /**
258  * Convert attributes string to Any type.
259  *
260  * @param   ouName      the string of attribute name.
261  * @param   ouValue     the string of attribute value.
262  * @param   rAny        the Any object to be returned.
263  */
get_AnyFromOLECHAR(std::u16string_view ouName,const OUString & ouValue,Any & rAny)264 void CAccEditableText::get_AnyFromOLECHAR(std::u16string_view ouName, const OUString &ouValue, Any &rAny)
265 {
266     if(ouName == u"CharBackColor" ||
267             ouName == u"CharColor" ||
268             ouName == u"ParaAdjust" ||
269             ouName == u"ParaFirstLineIndent" ||
270             ouName == u"ParaLeftMargin" ||
271             ouName == u"ParaRightMargin" ||
272             ouName == u"ParaTopMargin" ||
273             ouName == u"ParaBottomMargin" ||
274             ouName == u"CharFontPitch" )
275     {
276         // Convert to int.
277         // NOTE: CharFontPitch is not implemented in java file.
278         sal_Int32 nValue = ouValue.toInt32();
279         rAny.setValue(&nValue, cppu::UnoType<sal_Int32>::get());
280     }
281     else if(ouName == u"CharShadowed" ||
282             ouName == u"CharContoured" )
283     {
284         // Convert to boolean.
285         rAny <<= ouValue.toBoolean();
286     }
287     else if(ouName == u"CharEscapement" ||
288             ouName == u"CharStrikeout"  ||
289             ouName == u"CharUnderline" ||
290             ouName == u"CharFontPitch" )
291     {
292         // Convert to short.
293         short nValue = static_cast<short>(ouValue.toInt32());
294         rAny.setValue(&nValue, cppu::UnoType<short>::get());
295     }
296     else if(ouName == u"CharHeight" ||
297             ouName == u"CharWeight" )
298     {
299         // Convert to float.
300         float fValue = ouValue.toFloat();
301         rAny.setValue(&fValue, cppu::UnoType<float>::get());
302     }
303     else if(ouName == u"CharFontName" )
304     {
305         // Convert to string.
306         rAny.setValue(&ouValue, cppu::UnoType<OUString>::get());
307     }
308     else if(ouName == u"CharPosture" )
309     {
310         // Convert to FontSlant.
311         css::awt::FontSlant fontSlant = static_cast<css::awt::FontSlant>(ouValue.toInt32());
312         rAny.setValue(&fontSlant, cppu::UnoType<css::awt::FontSlant>::get());
313     }
314     else if(ouName == u"ParaTabStops" )
315     {
316 
317         // Convert to the Sequence with TabStop element.
318         vector< css::style::TabStop > vecTabStop;
319         css::style::TabStop tabStop;
320         OUString ouSubValue;
321         sal_Int32 pos = 0, posComma = 0;
322 
323         do
324         {
325             // Position.
326             pos = ouValue.indexOf("Position=", pos);
327             if(pos != -1)
328             {
329                 posComma = ouValue.indexOf(',', pos + 9); // 9 = length of "Position=".
330                 if(posComma != -1)
331                 {
332                     ouSubValue = ouValue.copy(pos + 9, posComma - pos - 9);
333                     tabStop.Position = ouSubValue.toInt32();
334                     pos = posComma + 1;
335 
336                     // TabAlign.
337                     pos = ouValue.indexOf("TabAlign=", pos);
338                     if(pos != -1)
339                     {
340                         posComma = ouValue.indexOf(',', pos + 9); // 9 = length of "TabAlign=".
341                         if(posComma != -1)
342                         {
343                             ouSubValue = ouValue.copy(pos + 9, posComma - pos - 9);
344                             tabStop.Alignment = static_cast<css::style::TabAlign>(ouSubValue.toInt32());
345                             pos = posComma + 1;
346 
347                             // DecimalChar.
348                             pos = ouValue.indexOf("DecimalChar=", pos);
349                             if(pos != -1)
350                             {
351                                 posComma = ouValue.indexOf(',', pos + 11); // 11 = length of "TabAlign=".
352                                 if(posComma != -1)
353                                 {
354                                     ouSubValue = ouValue.copy(pos + 11, posComma - pos - 11);
355                                     tabStop.DecimalChar = ouSubValue.toChar();
356                                     pos = posComma + 1;
357 
358                                     // FillChar.
359                                     pos = ouValue.indexOf("FillChar=", pos);
360                                     if(pos != -1)
361                                     {
362                                         posComma = ouValue.indexOf(',', pos + 9); // 9 = length of "TabAlign=".
363                                         if(posComma != -1)
364                                         {
365                                             ouSubValue = ouValue.copy(pos + 9, posComma - pos - 9);
366                                             tabStop.DecimalChar = ouSubValue.toChar();
367                                             pos = posComma + 1;
368 
369                                             // Complete TabStop element.
370                                             vecTabStop.push_back(tabStop);
371                                         }
372                                         else
373                                             break;  // No match comma.
374                                     }
375                                     else
376                                         break;  // No match FillChar.
377                                 }
378                                 else
379                                     break;  // No match comma.
380                             }
381                             else
382                                 break;  // No match DecimalChar.
383                         }
384                         else
385                             break;  // No match comma.
386                     }
387                     else
388                         break;  // No match TabAlign.
389                 }
390                 else
391                     break;  // No match comma.
392             }
393             else
394                 break;  // No match Position.
395         }
396         while(pos < ouValue.getLength());
397 
398 
399         // Dump into Sequence.
400         int iSeqLen = (vecTabStop.size() == 0) ? 1 : vecTabStop.size();
401         Sequence< css::style::TabStop > seqTabStop(iSeqLen);
402 
403         if(vecTabStop.size() != 0)
404         {
405             // Dump every element.
406             for(int i = 0; i < iSeqLen; i ++)
407             {
408                 seqTabStop[i] = vecTabStop[i];
409             }
410         }
411         else
412         {
413             // Create default value.
414             seqTabStop[0].Position = 0;
415             seqTabStop[0].Alignment = css::style::TabAlign_DEFAULT;
416             seqTabStop[0].DecimalChar = '.';
417             seqTabStop[0].FillChar = ' ';
418         }
419 
420         // Assign to Any object.
421         rAny.setValue(&seqTabStop, cppu::UnoType<Sequence< css::style::TabStop >>::get());
422     }
423     else if(ouName == u"ParaLineSpacing" )
424     {
425         // Parse value string.
426         css::style::LineSpacing lineSpacing;
427         OUString ouSubValue;
428         sal_Int32 pos = 0, posComma = 0;
429 
430         pos = ouValue.indexOf("Mode=", pos);
431         if(pos != -1)
432         {
433             posComma = ouValue.indexOf(',', pos + 5); // 5 = length of "Mode=".
434             if(posComma != -1)
435             {
436                 ouSubValue = ouValue.copy(pos + 5, posComma - pos - 5);
437                 lineSpacing.Mode = static_cast<sal_Int16>(ouSubValue.toInt32());
438                 pos = posComma + 1;
439 
440                 pos = ouValue.indexOf("Height=", pos);
441                 if(pos != -1)
442                 {
443                     ouSubValue = ouValue.copy(pos + 7);
444                     lineSpacing.Height = static_cast<sal_Int16>(ouSubValue.toInt32());
445                 }
446                 else
447                 {
448                     lineSpacing.Height = sal_Int16(100);    // Default height.
449                 }
450             }
451             else
452             {
453                 lineSpacing.Height = sal_Int16(100);    // Default height.
454             }
455         }
456         else
457         {
458             // Default Mode and Height.
459             lineSpacing.Mode = sal_Int16(0);
460             lineSpacing.Height = sal_Int16(100);    // Default height.
461         }
462 
463         // Convert to Any object.
464         rAny.setValue(&lineSpacing, cppu::UnoType<css::style::LineSpacing>::get());
465     }
466     else
467     {
468         // Do nothing.
469         sal_Int32 nDefault = 0;
470         rAny.setValue(&nDefault, cppu::UnoType<sal_Int32>::get());
471     }
472 }
473 
474 /**
475  * Override of IUNOXWrapper.
476  *
477  * @param    pXInterface    the pointer of UNO interface.
478  */
put_XInterface(hyper pXInterface)479 COM_DECLSPEC_NOTHROW STDMETHODIMP CAccEditableText::put_XInterface(hyper pXInterface)
480 {
481     // internal IUNOXWrapper - no mutex meeded
482 
483     ENTER_PROTECTED_BLOCK
484 
485     CUNOXWrapper::put_XInterface(pXInterface);
486     //special query.
487     if(pUNOInterface == nullptr)
488         return E_FAIL;
489     Reference<XAccessibleContext> pRContext = pUNOInterface->getAccessibleContext();
490     if( !pRContext.is() )
491     {
492         return E_FAIL;
493     }
494     Reference<XAccessibleEditableText> pRXI(pRContext,UNO_QUERY);
495     if( !pRXI.is() )
496         pRXEdtTxt = nullptr;
497     else
498         pRXEdtTxt = pRXI.get();
499     return S_OK;
500 
501     LEAVE_PROTECTED_BLOCK
502 }
503 
504 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
505