Bug Summary

File:home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx
Warning:line 3037, column 5
Undefined or garbage value returned to caller

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name accpara.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /usr/include/libxml2 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SW_DLLIMPLEMENTATION -D SWUI_DLL_NAME="libswuilo.so" -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/sw/source/core/inc -I /home/maarten/src/libreoffice/core/sw/source/filter/inc -I /home/maarten/src/libreoffice/core/sw/source/uibase/inc -I /home/maarten/src/libreoffice/core/sw/inc -I /home/maarten/src/libreoffice/core/workdir/SdiTarget/sw/sdi -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/sw/generated -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/oovbaapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx
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#include <memory>
21#include <numeric>
22#include <txtfrm.hxx>
23#include <flyfrm.hxx>
24#include <mdiexp.hxx>
25#include <ndtxt.hxx>
26#include <pam.hxx>
27#include <unotextrange.hxx>
28#include <unocrsrhelper.hxx>
29#include <crstate.hxx>
30#include <accmap.hxx>
31#include <fesh.hxx>
32#include <viewopt.hxx>
33#include <osl/mutex.hxx>
34#include <vcl/svapp.hxx>
35#include <vcl/window.hxx>
36#include <sal/log.hxx>
37#include <com/sun/star/accessibility/AccessibleRole.hpp>
38#include <com/sun/star/accessibility/AccessibleScrollType.hpp>
39#include <com/sun/star/accessibility/AccessibleStateType.hpp>
40#include <com/sun/star/accessibility/AccessibleTextType.hpp>
41#include <com/sun/star/accessibility/AccessibleEventId.hpp>
42#include <unotools/accessiblestatesethelper.hxx>
43#include <com/sun/star/i18n/Boundary.hpp>
44#include <com/sun/star/i18n/CharacterIteratorMode.hpp>
45#include <com/sun/star/i18n/WordType.hpp>
46#include <com/sun/star/i18n/XBreakIterator.hpp>
47#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
48#include <com/sun/star/beans/UnknownPropertyException.hpp>
49#include <breakit.hxx>
50#include "accpara.hxx"
51#include "accportions.hxx"
52#include <sfx2/viewsh.hxx>
53#include <sfx2/viewfrm.hxx>
54#include <sfx2/dispatch.hxx>
55#include <unocrsr.hxx>
56#include <unoport.hxx>
57#include <doc.hxx>
58#include <IDocumentRedlineAccess.hxx>
59#include "acchyperlink.hxx"
60#include "acchypertextdata.hxx"
61#include <unotools/accessiblerelationsethelper.hxx>
62#include <com/sun/star/accessibility/AccessibleRelationType.hpp>
63#include <comphelper/accessibletexthelper.hxx>
64#include <algorithm>
65#include <docufld.hxx>
66#include <txtfld.hxx>
67#include <fmtfld.hxx>
68#include <modcfg.hxx>
69#include <com/sun/star/beans/XPropertySet.hpp>
70#include <swmodule.hxx>
71#include <redline.hxx>
72#include <com/sun/star/awt/FontWeight.hpp>
73#include <com/sun/star/awt/FontStrikeout.hpp>
74#include <com/sun/star/awt/FontSlant.hpp>
75#include <wrong.hxx>
76#include <editeng/brushitem.hxx>
77#include <editeng/unoprnms.hxx>
78#include <swatrset.hxx>
79#include <unosett.hxx>
80#include <unomap.hxx>
81#include <unoprnms.hxx>
82#include <com/sun/star/text/WritingMode2.hpp>
83#include <viewimp.hxx>
84#include "textmarkuphelper.hxx"
85#include "parachangetrackinginfo.hxx"
86#include <com/sun/star/text/TextMarkupType.hpp>
87#include <cppuhelper/supportsservice.hxx>
88#include <cppuhelper/typeprovider.hxx>
89#include <svx/colorwindow.hxx>
90#include <editeng/editids.hrc>
91
92#include <reffld.hxx>
93#include <flddat.hxx>
94#include "../../uibase/inc/fldmgr.hxx"
95#include <fldbas.hxx> // SwField
96
97using namespace ::com::sun::star;
98using namespace ::com::sun::star::accessibility;
99using namespace ::com::sun::star::container;
100
101using beans::PropertyValue;
102using beans::XMultiPropertySet;
103using beans::UnknownPropertyException;
104using beans::PropertyState_DIRECT_VALUE;
105
106using std::max;
107using std::min;
108using std::sort;
109
110namespace com::sun::star::text {
111 class XText;
112}
113
114const char sServiceName[] = "com.sun.star.text.AccessibleParagraphView";
115const char sImplementationName[] = "com.sun.star.comp.Writer.SwAccessibleParagraphView";
116
117OUString const & SwAccessibleParagraph::GetString()
118{
119 return GetPortionData().GetAccessibleString();
120}
121
122OUString SwAccessibleParagraph::GetDescription()
123{
124 return OUString(); // provide empty description for paragraphs
125}
126
127sal_Int32 SwAccessibleParagraph::GetCaretPos()
128{
129 sal_Int32 nRet = -1;
130
131 // get the selection's point, and test whether it's in our node
132 // #i27301# - consider adjusted method signature
133 SwPaM* pCaret = GetCursor( false ); // caret is first PaM in PaM-ring
134
135 if( pCaret != nullptr )
136 {
137 SwTextFrame const*const pTextFrame(static_cast<SwTextFrame const*>(GetFrame()));
138 assert(pTextFrame)(static_cast <bool> (pTextFrame) ? void (0) : __assert_fail
("pTextFrame", "/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
, 138, __extension__ __PRETTY_FUNCTION__))
;
139
140 // check whether the point points into 'our' node
141 SwPosition* pPoint = pCaret->GetPoint();
142 if (sw::FrameContainsNode(*pTextFrame, pPoint->nNode.GetIndex()))
143 {
144 // same node? Then check whether it's also within 'our' part
145 // of the paragraph
146 const TextFrameIndex nIndex = pTextFrame->MapModelToViewPos(*pPoint);
147 if(!GetPortionData().IsValidCorePosition( nIndex ) ||
148 (GetPortionData().IsZeroCorePositionData()
149 && nIndex == TextFrameIndex(0)))
150 {
151 bool bFormat = pTextFrame->HasPara();
152 if(bFormat)
153 {
154 ClearPortionData();
155 UpdatePortionData();
156 }
157 }
158 if( GetPortionData().IsValidCorePosition( nIndex ) )
159 {
160 // Yes, it's us!
161 // consider that cursor/caret is in front of the list label
162 if ( pCaret->IsInFrontOfLabel() )
163 {
164 nRet = 0;
165 }
166 else
167 {
168 nRet = GetPortionData().GetAccessiblePosition( nIndex );
169 }
170
171 OSL_ENSURE( nRet >= 0, "invalid cursor?" )do { if (true && (!(nRet >= 0))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "171" ": "), "%s", "invalid cursor?"); } } while (false)
;
172 OSL_ENSURE( nRet <= GetPortionData().GetAccessibleString().do { if (true && (!(nRet <= GetPortionData().GetAccessibleString
(). getLength()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "173" ": "), "%s", "invalid cursor?"); } } while (false)
173 getLength(), "invalid cursor?" )do { if (true && (!(nRet <= GetPortionData().GetAccessibleString
(). getLength()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "173" ": "), "%s", "invalid cursor?"); } } while (false)
;
174 }
175 // else: in this paragraph, but in different frame
176 }
177 // else: not in this paragraph
178 }
179 // else: no cursor -> no caret
180
181 return nRet;
182}
183
184// #i27301# - new parameter <_bForSelection>
185SwPaM* SwAccessibleParagraph::GetCursor( const bool _bForSelection )
186{
187 // get the cursor shell; if we don't have any, we don't have a
188 // cursor/selection either
189 SwPaM* pCursor = nullptr;
190 SwCursorShell* pCursorShell = SwAccessibleParagraph::GetCursorShell();
191 // #i27301# - if cursor is retrieved for selection, the cursors for
192 // a table selection has to be returned.
193 if ( pCursorShell != nullptr &&
194 ( _bForSelection || !pCursorShell->IsTableMode() ) )
195 {
196 SwFEShell *pFESh = dynamic_cast<const SwFEShell*>( pCursorShell) != nullptr
197 ? static_cast< SwFEShell * >( pCursorShell ) : nullptr;
198 if( !pFESh ||
199 !(pFESh->IsFrameSelected() || pFESh->IsObjSelected() > 0) )
200 {
201 // get the selection, and test whether it affects our text node
202 pCursor = pCursorShell->GetCursor( false /* ??? */ );
203 }
204 }
205
206 return pCursor;
207}
208
209bool SwAccessibleParagraph::IsHeading() const
210{
211 SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(GetFrame()));
212 const SwTextNode *pTextNd = pFrame->GetTextNodeForParaProps();
213 return pTextNd->IsOutline();
214}
215
216void SwAccessibleParagraph::GetStates(
217 ::utl::AccessibleStateSetHelper& rStateSet )
218{
219 SwAccessibleContext::GetStates( rStateSet );
220
221 // MULTILINE
222 rStateSet.AddState( AccessibleStateType::MULTI_LINE );
223
224 if (GetCursorShell())
225 {
226 // MULTISELECTABLE
227 rStateSet.AddState(AccessibleStateType::MULTI_SELECTABLE);
228 // FOCUSABLE
229 rStateSet.AddState(AccessibleStateType::FOCUSABLE);
230 }
231
232 // FOCUSED (simulates node index of cursor)
233 SwPaM* pCaret = GetCursor( false ); // #i27301# - consider adjusted method signature
234 SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(GetFrame()));
235 assert(pFrame)(static_cast <bool> (pFrame) ? void (0) : __assert_fail
("pFrame", "/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
, 235, __extension__ __PRETTY_FUNCTION__))
;
236 if (pCaret != nullptr &&
237 sw::FrameContainsNode(*pFrame, pCaret->GetPoint()->nNode.GetIndex()) &&
238 m_nOldCaretPos != -1)
239 {
240 vcl::Window *pWin = GetWindow();
241 if( pWin && pWin->HasFocus() )
242 rStateSet.AddState( AccessibleStateType::FOCUSED );
243 ::rtl::Reference < SwAccessibleContext > xThis( this );
244 GetMap()->SetCursorContext( xThis );
245 }
246}
247
248void SwAccessibleParagraph::InvalidateContent_( bool bVisibleDataFired )
249{
250 OUString sOldText( GetString() );
251
252 ClearPortionData();
253
254 const OUString& rText = GetString();
255
256 if( rText != sOldText )
257 {
258 // The text is changed
259 AccessibleEventObject aEvent;
260 aEvent.EventId = AccessibleEventId::TEXT_CHANGED;
261
262 // determine exact changes between sOldText and rText
263 (void)comphelper::OCommonAccessibleText::implInitTextChangedEvent(sOldText, rText,
264 aEvent.OldValue,
265 aEvent.NewValue);
266
267 FireAccessibleEvent( aEvent );
268 uno::Reference< XAccessible > xparent = getAccessibleParent();
269 uno::Reference< XAccessibleContext > xAccContext(xparent,uno::UNO_QUERY);
270 if (xAccContext.is() && xAccContext->getAccessibleRole() == AccessibleRole::TABLE_CELL)
271 {
272 SwAccessibleContext* pPara = static_cast< SwAccessibleContext* >(xparent.get());
273 if(pPara)
274 {
275 AccessibleEventObject aParaEvent;
276 aParaEvent.EventId = AccessibleEventId::VALUE_CHANGED;
277 pPara->FireAccessibleEvent(aParaEvent);
278 }
279 }
280 }
281 else if( !bVisibleDataFired )
282 {
283 FireVisibleDataEvent();
284 }
285
286 bool bNewIsHeading = IsHeading();
287 //Get the real heading level, Heading1 ~ Heading10
288 m_nHeadingLevel = GetRealHeadingLevel();
289 bool bOldIsHeading;
290 {
291 osl::MutexGuard aGuard( m_Mutex );
292 bOldIsHeading = m_bIsHeading;
293 if( m_bIsHeading != bNewIsHeading )
294 m_bIsHeading = bNewIsHeading;
295 }
296
297 if( bNewIsHeading != bOldIsHeading )
298 {
299 // The role has changed
300 AccessibleEventObject aEvent;
301 aEvent.EventId = AccessibleEventId::ROLE_CHANGED;
302
303 FireAccessibleEvent( aEvent );
304 }
305
306 if( rText == sOldText )
307 return;
308
309 OUString sNewDesc( GetDescription() );
310 OUString sOldDesc;
311 {
312 osl::MutexGuard aGuard( m_Mutex );
313 sOldDesc = m_sDesc;
314 if( m_sDesc != sNewDesc )
315 m_sDesc = sNewDesc;
316 }
317
318 if( sNewDesc != sOldDesc )
319 {
320 // The text is changed
321 AccessibleEventObject aEvent;
322 aEvent.EventId = AccessibleEventId::DESCRIPTION_CHANGED;
323 aEvent.OldValue <<= sOldDesc;
324 aEvent.NewValue <<= sNewDesc;
325
326 FireAccessibleEvent( aEvent );
327 }
328}
329
330void SwAccessibleParagraph::InvalidateCursorPos_()
331{
332 // The text is changed
333 sal_Int32 nNew = GetCaretPos();
334 sal_Int32 nOld;
335 {
336 osl::MutexGuard aGuard( m_Mutex );
337 nOld = m_nOldCaretPos;
338 m_nOldCaretPos = nNew;
339 }
340 if( -1 != nNew )
341 {
342 // remember that object as the one that has the caret. This is
343 // necessary to notify that object if the cursor leaves it.
344 ::rtl::Reference < SwAccessibleContext > xThis( this );
345 GetMap()->SetCursorContext( xThis );
346 }
347
348 vcl::Window *pWin = GetWindow();
349 if( nOld == nNew )
350 return;
351
352 // The cursor's node position is simulated by the focus!
353 if( pWin && pWin->HasFocus() && -1 == nOld )
354 FireStateChangedEvent( AccessibleStateType::FOCUSED, true );
355
356 AccessibleEventObject aEvent;
357 aEvent.EventId = AccessibleEventId::CARET_CHANGED;
358 aEvent.OldValue <<= nOld;
359 aEvent.NewValue <<= nNew;
360
361 FireAccessibleEvent( aEvent );
362
363 if( pWin && pWin->HasFocus() && -1 == nNew )
364 FireStateChangedEvent( AccessibleStateType::FOCUSED, false );
365 //To send TEXT_SELECTION_CHANGED event
366 sal_Int32 nStart=0;
367 sal_Int32 nEnd =0;
368 bool bCurSelection = GetSelection(nStart,nEnd);
369 if(m_bLastHasSelection || bCurSelection )
370 {
371 aEvent.EventId = AccessibleEventId::TEXT_SELECTION_CHANGED;
372 aEvent.OldValue.clear();
373 aEvent.NewValue.clear();
374 FireAccessibleEvent(aEvent);
375 }
376 m_bLastHasSelection =bCurSelection;
377
378}
379
380void SwAccessibleParagraph::InvalidateFocus_()
381{
382 vcl::Window *pWin = GetWindow();
383 if( pWin )
384 {
385 sal_Int32 nPos;
386 {
387 osl::MutexGuard aGuard( m_Mutex );
388 nPos = m_nOldCaretPos;
389 }
390 OSL_ENSURE( nPos != -1, "focus object should be selected" )do { if (true && (!(nPos != -1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "390" ": "), "%s", "focus object should be selected"); }
} while (false)
;
391
392 FireStateChangedEvent( AccessibleStateType::FOCUSED,
393 pWin->HasFocus() && nPos != -1 );
394 }
395}
396
397SwAccessibleParagraph::SwAccessibleParagraph(
398 std::shared_ptr<SwAccessibleMap> const& pInitMap,
399 const SwTextFrame& rTextFrame )
400 : SwAccessibleContext( pInitMap, AccessibleRole::PARAGRAPH, &rTextFrame )
401 , m_sDesc()
402 , m_nOldCaretPos( -1 )
403 , m_bIsHeading( false )
404 //Get the real heading level, Heading1 ~ Heading10
405 , m_nHeadingLevel (-1)
406 , m_aSelectionHelper( *this )
407 , mpParaChangeTrackInfo( new SwParaChangeTrackingInfo( rTextFrame ) ) // #i108125#
408 , m_bLastHasSelection(false) //To add TEXT_SELECTION_CHANGED event
409{
410 StartListening(const_cast<SwTextFrame&>(rTextFrame));
411 m_bIsHeading = IsHeading();
412 //Get the real heading level, Heading1 ~ Heading10
413 m_nHeadingLevel = GetRealHeadingLevel();
414 SetName( OUString() ); // set an empty accessibility name for paragraphs
415
416 // If this object has the focus, then it is remembered by the map itself.
417 m_nOldCaretPos = GetCaretPos();
418}
419
420SwAccessibleParagraph::~SwAccessibleParagraph()
421{
422 SolarMutexGuard aGuard;
423
424 m_pPortionData.reset();
425 m_pHyperTextData.reset();
426 mpParaChangeTrackInfo.reset(); // #i108125#
427 EndListeningAll();
428}
429
430bool SwAccessibleParagraph::HasCursor()
431{
432 osl::MutexGuard aGuard( m_Mutex );
433 return m_nOldCaretPos != -1;
434}
435
436void SwAccessibleParagraph::UpdatePortionData()
437{
438 // obtain the text frame
439 OSL_ENSURE( GetFrame() != nullptr, "The text frame has vanished!" )do { if (true && (!(GetFrame() != nullptr))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "439" ": "), "%s", "The text frame has vanished!"); } } while
(false)
;
440 OSL_ENSURE( GetFrame()->IsTextFrame(), "The text frame has mutated!" )do { if (true && (!(GetFrame()->IsTextFrame()))) {
sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "440" ": "), "%s", "The text frame has mutated!"); } } while
(false)
;
441 const SwTextFrame* pFrame = static_cast<const SwTextFrame*>( GetFrame() );
442
443 // build new portion data
444 m_pPortionData.reset( new SwAccessiblePortionData(
445 pFrame, GetMap()->GetShell()->GetViewOptions()) );
446 pFrame->VisitPortions( *m_pPortionData );
447
448 OSL_ENSURE( m_pPortionData != nullptr, "UpdatePortionData() failed" )do { if (true && (!(m_pPortionData != nullptr))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "448" ": "), "%s", "UpdatePortionData() failed"); } } while
(false)
;
449}
450
451void SwAccessibleParagraph::ClearPortionData()
452{
453 m_pPortionData.reset();
454 m_pHyperTextData.reset();
455}
456
457void SwAccessibleParagraph::ExecuteAtViewShell( sal_uInt16 nSlot )
458{
459 OSL_ENSURE( GetMap() != nullptr, "no map?" )do { if (true && (!(GetMap() != nullptr))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "459" ": "), "%s", "no map?"); } } while (false)
;
460 SwViewShell* pViewShell = GetMap()->GetShell();
461
462 OSL_ENSURE( pViewShell != nullptr, "View shell expected!" )do { if (true && (!(pViewShell != nullptr))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "462" ": "), "%s", "View shell expected!"); } } while (false
)
;
463 SfxViewShell* pSfxShell = pViewShell->GetSfxViewShell();
464
465 OSL_ENSURE( pSfxShell != nullptr, "SfxViewShell shell expected!" )do { if (true && (!(pSfxShell != nullptr))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "465" ": "), "%s", "SfxViewShell shell expected!"); } } while
(false)
;
466 if( !pSfxShell )
467 return;
468
469 SfxViewFrame *pFrame = pSfxShell->GetViewFrame();
470 OSL_ENSURE( pFrame != nullptr, "View frame expected!" )do { if (true && (!(pFrame != nullptr))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "470" ": "), "%s", "View frame expected!"); } } while (false
)
;
471 if( !pFrame )
472 return;
473
474 SfxDispatcher *pDispatcher = pFrame->GetDispatcher();
475 OSL_ENSURE( pDispatcher != nullptr, "Dispatcher expected!" )do { if (true && (!(pDispatcher != nullptr))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "475" ": "), "%s", "Dispatcher expected!"); } } while (false
)
;
476 if( !pDispatcher )
477 return;
478
479 pDispatcher->Execute( nSlot );
480}
481
482SwXTextPortion* SwAccessibleParagraph::CreateUnoPortion(
483 sal_Int32 nStartIndex,
484 sal_Int32 nEndIndex )
485{
486 OSL_ENSURE( (IsValidChar(nStartIndex, GetString().getLength()) &&do { if (true && (!((IsValidChar(nStartIndex, GetString
().getLength()) && (nEndIndex == -1)) || IsValidRange
(nStartIndex, nEndIndex, GetString().getLength())))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "489" ": "), "%s", "please check parameters before calling this method"
); } } while (false)
487 (nEndIndex == -1)) ||do { if (true && (!((IsValidChar(nStartIndex, GetString
().getLength()) && (nEndIndex == -1)) || IsValidRange
(nStartIndex, nEndIndex, GetString().getLength())))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "489" ": "), "%s", "please check parameters before calling this method"
); } } while (false)
488 IsValidRange(nStartIndex, nEndIndex, GetString().getLength()),do { if (true && (!((IsValidChar(nStartIndex, GetString
().getLength()) && (nEndIndex == -1)) || IsValidRange
(nStartIndex, nEndIndex, GetString().getLength())))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "489" ": "), "%s", "please check parameters before calling this method"
); } } while (false)
489 "please check parameters before calling this method" )do { if (true && (!((IsValidChar(nStartIndex, GetString
().getLength()) && (nEndIndex == -1)) || IsValidRange
(nStartIndex, nEndIndex, GetString().getLength())))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "489" ": "), "%s", "please check parameters before calling this method"
); } } while (false)
;
490
491 const TextFrameIndex nStart = GetPortionData().GetCoreViewPosition(nStartIndex);
492 const TextFrameIndex nEnd = (nEndIndex == -1)
493 ? (nStart + TextFrameIndex(1))
494 : GetPortionData().GetCoreViewPosition(nEndIndex);
495
496 // create UNO cursor
497 SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(GetFrame()));
498 SwPosition aStartPos(pFrame->MapViewToModelPos(nStart));
499 auto pUnoCursor(const_cast<SwDoc&>(pFrame->GetDoc()).CreateUnoCursor(aStartPos));
500 pUnoCursor->SetMark();
501 *pUnoCursor->GetMark() = pFrame->MapViewToModelPos(nEnd);
502
503 // create a (dummy) text portion to be returned
504 uno::Reference<text::XText> aEmpty;
505 SwXTextPortion* pPortion =
506 new SwXTextPortion ( pUnoCursor.get(), aEmpty, PORTION_TEXT);
507
508 return pPortion;
509}
510
511// range checking for parameter
512
513bool SwAccessibleParagraph::IsValidChar(
514 sal_Int32 nPos, sal_Int32 nLength)
515{
516 return (nPos >= 0) && (nPos < nLength);
517}
518
519bool SwAccessibleParagraph::IsValidPosition(
520 sal_Int32 nPos, sal_Int32 nLength)
521{
522 return (nPos >= 0) && (nPos <= nLength);
523}
524
525bool SwAccessibleParagraph::IsValidRange(
526 sal_Int32 nBegin, sal_Int32 nEnd, sal_Int32 nLength)
527{
528 return IsValidPosition(nBegin, nLength) && IsValidPosition(nEnd, nLength);
529}
530
531//the function is to check whether the position is in a redline range.
532const SwRangeRedline* SwAccessibleParagraph::GetRedlineAtIndex()
533{
534 const SwRangeRedline* pRedline = nullptr;
535 SwPaM* pCrSr = GetCursor( true );
536 if ( pCrSr )
537 {
538 SwPosition* pStart = pCrSr->Start();
539 pRedline = pStart->GetDoc().getIDocumentRedlineAccess().GetRedline(*pStart, nullptr);
540 }
541
542 return pRedline;
543}
544
545// text boundaries
546
547bool SwAccessibleParagraph::GetCharBoundary(
548 i18n::Boundary& rBound,
549 sal_Int32 nPos )
550{
551 if( GetPortionData().FillBoundaryIFDateField( rBound, nPos) )
552 return true;
553
554 rBound.startPos = nPos;
555 rBound.endPos = nPos+1;
556 return true;
557}
558
559bool SwAccessibleParagraph::GetWordBoundary(
560 i18n::Boundary& rBound,
561 const OUString& rText,
562 sal_Int32 nPos )
563{
564 // now ask the Break-Iterator for the word
565 assert(g_pBreakIt && g_pBreakIt->GetBreakIter().is())(static_cast <bool> (g_pBreakIt && g_pBreakIt->
GetBreakIter().is()) ? void (0) : __assert_fail ("g_pBreakIt && g_pBreakIt->GetBreakIter().is()"
, "/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
, 565, __extension__ __PRETTY_FUNCTION__))
;
566
567 // get locale for this position
568 SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(GetFrame()));
569 const TextFrameIndex nCorePos = GetPortionData().GetCoreViewPosition(nPos);
570 lang::Locale aLocale = g_pBreakIt->GetLocale(pFrame->GetLangOfChar(nCorePos, 0, true));
571
572 // which type of word are we interested in?
573 // (DICTIONARY_WORD includes punctuation, ANY_WORD doesn't.)
574 const sal_Int16 nWordType = i18n::WordType::ANY_WORD;
575
576 // get word boundary, as the Break-Iterator sees fit.
577 rBound = g_pBreakIt->GetBreakIter()->getWordBoundary(
578 rText, nPos, aLocale, nWordType, true );
579
580 return true;
581}
582
583bool SwAccessibleParagraph::GetSentenceBoundary(
584 i18n::Boundary& rBound,
585 const OUString& rText,
586 sal_Int32 nPos )
587{
588 const sal_Unicode* pStr = rText.getStr();
589 while( nPos < rText.getLength() && pStr[nPos] == u' ' )
590 nPos++;
591
592 GetPortionData().GetSentenceBoundary( rBound, nPos );
593 return true;
594}
595
596bool SwAccessibleParagraph::GetLineBoundary(
597 i18n::Boundary& rBound,
598 const OUString& rText,
599 sal_Int32 nPos )
600{
601 if( rText.getLength() == nPos )
602 GetPortionData().GetLastLineBoundary( rBound );
603 else
604 GetPortionData().GetLineBoundary( rBound, nPos );
605 return true;
606}
607
608bool SwAccessibleParagraph::GetParagraphBoundary(
609 i18n::Boundary& rBound,
610 const OUString& rText )
611{
612 rBound.startPos = 0;
613 rBound.endPos = rText.getLength();
614 return true;
615}
616
617bool SwAccessibleParagraph::GetAttributeBoundary(
618 i18n::Boundary& rBound,
619 sal_Int32 nPos )
620{
621 GetPortionData().GetAttributeBoundary( rBound, nPos );
622 return true;
623}
624
625bool SwAccessibleParagraph::GetGlyphBoundary(
626 i18n::Boundary& rBound,
627 const OUString& rText,
628 sal_Int32 nPos )
629{
630 // ask the Break-Iterator for the glyph by moving one cell
631 // forward, and then one cell back
632 assert(g_pBreakIt && g_pBreakIt->GetBreakIter().is())(static_cast <bool> (g_pBreakIt && g_pBreakIt->
GetBreakIter().is()) ? void (0) : __assert_fail ("g_pBreakIt && g_pBreakIt->GetBreakIter().is()"
, "/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
, 632, __extension__ __PRETTY_FUNCTION__))
;
633
634 // get locale for this position
635 SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(GetFrame()));
636 const TextFrameIndex nCorePos = GetPortionData().GetCoreViewPosition(nPos);
637 lang::Locale aLocale = g_pBreakIt->GetLocale(pFrame->GetLangOfChar(nCorePos, 0, true));
638
639 // get word boundary, as the Break-Iterator sees fit.
640 const sal_Int16 nIterMode = i18n::CharacterIteratorMode::SKIPCELL;
641 sal_Int32 nDone = 0;
642 rBound.endPos = g_pBreakIt->GetBreakIter()->nextCharacters(
643 rText, nPos, aLocale, nIterMode, 1, nDone );
644 rBound.startPos = g_pBreakIt->GetBreakIter()->previousCharacters(
645 rText, rBound.endPos, aLocale, nIterMode, 1, nDone );
646 bool bRet = ((rBound.startPos <= nPos) && (nPos <= rBound.endPos));
647 OSL_ENSURE( rBound.startPos <= nPos, "start pos too high" )do { if (true && (!(rBound.startPos <= nPos))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "647" ": "), "%s", "start pos too high"); } } while (false
)
;
648 OSL_ENSURE( rBound.endPos >= nPos, "end pos too low" )do { if (true && (!(rBound.endPos >= nPos))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "648" ": "), "%s", "end pos too low"); } } while (false)
;
649
650 return bRet;
651}
652
653bool SwAccessibleParagraph::GetTextBoundary(
654 i18n::Boundary& rBound,
655 const OUString& rText,
656 sal_Int32 nPos,
657 sal_Int16 nTextType )
658{
659 // error checking
660 if( !( AccessibleTextType::LINE == nTextType
661 ? IsValidPosition( nPos, rText.getLength() )
662 : IsValidChar( nPos, rText.getLength() ) ) )
663 throw lang::IndexOutOfBoundsException();
664
665 bool bRet;
666
667 switch( nTextType )
668 {
669 case AccessibleTextType::WORD:
670 bRet = GetWordBoundary(rBound, rText, nPos);
671 break;
672
673 case AccessibleTextType::SENTENCE:
674 bRet = GetSentenceBoundary( rBound, rText, nPos );
675 break;
676
677 case AccessibleTextType::PARAGRAPH:
678 bRet = GetParagraphBoundary( rBound, rText );
679 break;
680
681 case AccessibleTextType::CHARACTER:
682 bRet = GetCharBoundary( rBound, nPos );
683 break;
684
685 case AccessibleTextType::LINE:
686 //Solve the problem of returning wrong LINE and PARAGRAPH
687 if((nPos == rText.getLength()) && nPos > 0)
688 bRet = GetLineBoundary( rBound, rText, nPos - 1);
689 else
690 bRet = GetLineBoundary( rBound, rText, nPos );
691 break;
692
693 case AccessibleTextType::ATTRIBUTE_RUN:
694 bRet = GetAttributeBoundary( rBound, nPos );
695 break;
696
697 case AccessibleTextType::GLYPH:
698 bRet = GetGlyphBoundary( rBound, rText, nPos );
699 break;
700
701 default:
702 throw lang::IllegalArgumentException( );
703 }
704
705 return bRet;
706}
707
708OUString SAL_CALL SwAccessibleParagraph::getAccessibleDescription()
709{
710 SolarMutexGuard aGuard;
711
712 ThrowIfDisposed();
713
714 osl::MutexGuard aGuard2( m_Mutex );
715 if( m_sDesc.isEmpty() )
716 m_sDesc = GetDescription();
717
718 return m_sDesc;
719}
720
721lang::Locale SAL_CALL SwAccessibleParagraph::getLocale()
722{
723 SolarMutexGuard aGuard;
724
725 const SwTextFrame *pTextFrame = dynamic_cast<const SwTextFrame*>( GetFrame() );
726 if( !pTextFrame )
727 {
728 throw uno::RuntimeException("no SwTextFrame", static_cast<cppu::OWeakObject*>(this));
729 }
730
731 lang::Locale aLoc(g_pBreakIt->GetLocale(pTextFrame->GetLangOfChar(TextFrameIndex(0), 0, true)));
732
733 return aLoc;
734}
735
736// #i27138# - paragraphs are in relation CONTENT_FLOWS_FROM and/or CONTENT_FLOWS_TO
737uno::Reference<XAccessibleRelationSet> SAL_CALL SwAccessibleParagraph::getAccessibleRelationSet()
738{
739 SolarMutexGuard aGuard;
740
741 ThrowIfDisposed();
742
743 utl::AccessibleRelationSetHelper* pHelper = new utl::AccessibleRelationSetHelper();
744
745 const SwTextFrame* pTextFrame = dynamic_cast<const SwTextFrame*>(GetFrame());
746 OSL_ENSURE( pTextFrame,do { if (true && (!(pTextFrame))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "747" ": "), "%s", "<SwAccessibleParagraph::getAccessibleRelationSet()> - missing text frame"
); } } while (false)
747 "<SwAccessibleParagraph::getAccessibleRelationSet()> - missing text frame")do { if (true && (!(pTextFrame))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "747" ": "), "%s", "<SwAccessibleParagraph::getAccessibleRelationSet()> - missing text frame"
); } } while (false)
;
748 if ( pTextFrame )
749 {
750 const SwContentFrame* pPrevContentFrame( pTextFrame->FindPrevCnt() );
751 if ( pPrevContentFrame )
752 {
753 uno::Sequence< uno::Reference<XInterface> > aSequence { GetMap()->GetContext( pPrevContentFrame ) };
754 AccessibleRelation aAccRel( AccessibleRelationType::CONTENT_FLOWS_FROM,
755 aSequence );
756 pHelper->AddRelation( aAccRel );
757 }
758
759 const SwContentFrame* pNextContentFrame( pTextFrame->FindNextCnt( true ) );
760 if ( pNextContentFrame )
761 {
762 uno::Sequence< uno::Reference<XInterface> > aSequence { GetMap()->GetContext( pNextContentFrame ) };
763 AccessibleRelation aAccRel( AccessibleRelationType::CONTENT_FLOWS_TO,
764 aSequence );
765 pHelper->AddRelation( aAccRel );
766 }
767 }
768
769 return pHelper;
770}
771
772void SAL_CALL SwAccessibleParagraph::grabFocus()
773{
774 SolarMutexGuard aGuard;
775
776 ThrowIfDisposed();
777
778 // get cursor shell
779 SwCursorShell *pCursorSh = GetCursorShell();
780 SwPaM *pCursor = GetCursor( false ); // #i27301# - consider new method signature
781 const SwTextFrame *pTextFrame = static_cast<const SwTextFrame*>( GetFrame() );
782
783 if (pCursorSh != nullptr &&
784 ( pCursor == nullptr ||
785 !sw::FrameContainsNode(*pTextFrame, pCursor->GetPoint()->nNode.GetIndex()) ||
786 !pTextFrame->IsInside(pTextFrame->MapModelToViewPos(*pCursor->GetPoint()))))
787 {
788 // create pam for selection
789 SwPosition const aStartPos(pTextFrame->MapViewToModelPos(pTextFrame->GetOffset()));
790 SwPaM aPaM( aStartPos );
791
792 // set PaM at cursor shell
793 Select( aPaM );
794
795 }
796
797 // ->#i13955#
798 vcl::Window * pWindow = GetWindow();
799
800 if (pWindow != nullptr)
801 pWindow->GrabFocus();
802 // <-#i13955#
803}
804
805// #i71385#
806static bool lcl_GetBackgroundColor( Color & rColor,
807 const SwFrame* pFrame,
808 SwCursorShell* pCursorSh )
809{
810 const SvxBrushItem* pBackgrdBrush = nullptr;
811 const Color* pSectionTOXColor = nullptr;
812 SwRect aDummyRect;
813 drawinglayer::attribute::SdrAllFillAttributesHelperPtr aFillAttributes;
814
815 if ( pFrame &&
816 pFrame->GetBackgroundBrush( aFillAttributes, pBackgrdBrush, pSectionTOXColor, aDummyRect, false, /*bConsiderTextBox=*/false ) )
817 {
818 if ( pSectionTOXColor )
819 {
820 rColor = *pSectionTOXColor;
821 return true;
822 }
823 else
824 {
825 rColor = pBackgrdBrush->GetColor();
826 return true;
827 }
828 }
829 else if ( pCursorSh )
830 {
831 rColor = pCursorSh->Imp()->GetRetoucheColor();
832 return true;
833 }
834
835 return false;
836}
837
838sal_Int32 SAL_CALL SwAccessibleParagraph::getForeground()
839{
840 SolarMutexGuard g;
841
842 Color aBackgroundCol;
843
844 if ( lcl_GetBackgroundColor( aBackgroundCol, GetFrame(), GetCursorShell() ) )
845 {
846 if ( aBackgroundCol.IsDark() )
847 {
848 return sal_Int32(COL_WHITE);
849 }
850 else
851 {
852 return sal_Int32(COL_BLACK);
853 }
854 }
855
856 return SwAccessibleContext::getForeground();
857}
858
859sal_Int32 SAL_CALL SwAccessibleParagraph::getBackground()
860{
861 SolarMutexGuard g;
862
863 Color aBackgroundCol;
864
865 if ( lcl_GetBackgroundColor( aBackgroundCol, GetFrame(), GetCursorShell() ) )
866 {
867 return sal_Int32(aBackgroundCol);
868 }
869
870 return SwAccessibleContext::getBackground();
871}
872
873OUString SAL_CALL SwAccessibleParagraph::getImplementationName()
874{
875 return sImplementationName;
876}
877
878sal_Bool SAL_CALL SwAccessibleParagraph::supportsService(
879 const OUString& sTestServiceName)
880{
881 return cppu::supportsService(this, sTestServiceName);
882}
883
884uno::Sequence< OUString > SAL_CALL SwAccessibleParagraph::getSupportedServiceNames()
885{
886 return { sServiceName, sAccessibleServiceName };
887}
888
889static uno::Sequence< OUString > const & getAttributeNames()
890{
891 static uno::Sequence< OUString > const aNames
892 {
893 // Add the font name to attribute list
894 // sorted list of strings
895 UNO_NAME_CHAR_BACK_COLOR"CharBackColor",
896 UNO_NAME_CHAR_COLOR"CharColor",
897 UNO_NAME_CHAR_CONTOURED"CharContoured",
898 UNO_NAME_CHAR_EMPHASIS"CharEmphasis",
899 UNO_NAME_CHAR_ESCAPEMENT"CharEscapement",
900 UNO_NAME_CHAR_FONT_NAME"CharFontName",
901 UNO_NAME_CHAR_HEIGHT"CharHeight",
902 UNO_NAME_CHAR_POSTURE"CharPosture",
903 UNO_NAME_CHAR_SHADOWED"CharShadowed",
904 UNO_NAME_CHAR_STRIKEOUT"CharStrikeout",
905 UNO_NAME_CHAR_UNDERLINE"CharUnderline",
906 UNO_NAME_CHAR_UNDERLINE_COLOR"CharUnderlineColor",
907 UNO_NAME_CHAR_WEIGHT"CharWeight",
908 };
909 return aNames;
910}
911
912static uno::Sequence< OUString > const & getSupplementalAttributeNames()
913{
914 static uno::Sequence< OUString > const aNames
915 {
916 // sorted list of strings
917 UNO_NAME_NUMBERING_LEVEL"NumberingLevel",
918 UNO_NAME_NUMBERING_RULES"NumberingRules",
919 UNO_NAME_PARA_ADJUST"ParaAdjust",
920 UNO_NAME_PARA_BOTTOM_MARGIN"ParaBottomMargin",
921 UNO_NAME_PARA_FIRST_LINE_INDENT"ParaFirstLineIndent",
922 UNO_NAME_PARA_LEFT_MARGIN"ParaLeftMargin",
923 UNO_NAME_PARA_LINE_SPACING"ParaLineSpacing",
924 UNO_NAME_PARA_RIGHT_MARGIN"ParaRightMargin",
925 UNO_NAME_TABSTOPS"ParaTabStops",
926 };
927 return aNames;
928}
929
930// XInterface
931
932uno::Any SwAccessibleParagraph::queryInterface( const uno::Type& rType )
933{
934 uno::Any aRet;
935 if ( rType == cppu::UnoType<XAccessibleText>::get())
936 {
937 uno::Reference<XAccessibleText> aAccText = static_cast<XAccessibleText *>(*this); // resolve ambiguity
938 aRet <<= aAccText;
939 }
940 else if ( rType == cppu::UnoType<XAccessibleEditableText>::get())
941 {
942 uno::Reference<XAccessibleEditableText> aAccEditText = this;
943 aRet <<= aAccEditText;
944 }
945 else if ( rType == cppu::UnoType<XAccessibleSelection>::get())
946 {
947 uno::Reference<XAccessibleSelection> aAccSel = this;
948 aRet <<= aAccSel;
949 }
950 else if ( rType == cppu::UnoType<XAccessibleHypertext>::get())
951 {
952 uno::Reference<XAccessibleHypertext> aAccHyp = this;
953 aRet <<= aAccHyp;
954 }
955 // #i63870#
956 // add interface com::sun:star:accessibility::XAccessibleTextAttributes
957 else if ( rType == cppu::UnoType<XAccessibleTextAttributes>::get())
958 {
959 uno::Reference<XAccessibleTextAttributes> aAccTextAttr = this;
960 aRet <<= aAccTextAttr;
961 }
962 // #i89175#
963 // add interface com::sun:star:accessibility::XAccessibleTextMarkup
964 else if ( rType == cppu::UnoType<XAccessibleTextMarkup>::get())
965 {
966 uno::Reference<XAccessibleTextMarkup> aAccTextMarkup = this;
967 aRet <<= aAccTextMarkup;
968 }
969 // add interface com::sun:star:accessibility::XAccessibleMultiLineText
970 else if ( rType == cppu::UnoType<XAccessibleMultiLineText>::get())
971 {
972 uno::Reference<XAccessibleMultiLineText> aAccMultiLineText = this;
973 aRet <<= aAccMultiLineText;
974 }
975 else if ( rType == cppu::UnoType<XAccessibleTextSelection>::get())
976 {
977 uno::Reference< css::accessibility::XAccessibleTextSelection > aTextExtension = this;
978 aRet <<= aTextExtension;
979 }
980 else if ( rType == cppu::UnoType<XAccessibleExtendedAttributes>::get())
981 {
982 uno::Reference<XAccessibleExtendedAttributes> xAttr = this;
983 aRet <<= xAttr;
984 }
985 else
986 {
987 aRet = SwAccessibleContext::queryInterface(rType);
988 }
989
990 return aRet;
991}
992
993// XTypeProvider
994uno::Sequence< uno::Type > SAL_CALL SwAccessibleParagraph::getTypes()
995{
996 // #i63870# - add type accessibility::XAccessibleTextAttributes
997 // #i89175# - add type accessibility::XAccessibleTextMarkup and
998 return cppu::OTypeCollection(
999 cppu::UnoType<XAccessibleEditableText>::get(),
1000 cppu::UnoType<XAccessibleTextAttributes>::get(),
1001 ::cppu::UnoType<XAccessibleSelection>::get(),
1002 cppu::UnoType<XAccessibleTextMarkup>::get(),
1003 cppu::UnoType<XAccessibleMultiLineText>::get(),
1004 cppu::UnoType<XAccessibleHypertext>::get(),
1005 SwAccessibleContext::getTypes() ).getTypes();
1006}
1007
1008uno::Sequence< sal_Int8 > SAL_CALL SwAccessibleParagraph::getImplementationId()
1009{
1010 return css::uno::Sequence<sal_Int8>();
1011}
1012
1013// XAccessibleText
1014
1015sal_Int32 SwAccessibleParagraph::getCaretPosition()
1016{
1017 SolarMutexGuard aGuard;
1018
1019 ThrowIfDisposed();
1020
1021 sal_Int32 nRet = GetCaretPos();
1022 {
1023 osl::MutexGuard aOldCaretPosGuard( m_Mutex );
1024 OSL_ENSURE( nRet == m_nOldCaretPos, "caret pos out of sync" )do { if (true && (!(nRet == m_nOldCaretPos))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "1024" ": "), "%s", "caret pos out of sync"); } } while (
false)
;
1025 m_nOldCaretPos = nRet;
1026 }
1027 if( -1 != nRet )
1028 {
1029 ::rtl::Reference < SwAccessibleContext > xThis( this );
1030 GetMap()->SetCursorContext( xThis );
1031 }
1032
1033 return nRet;
1034}
1035
1036sal_Bool SAL_CALL SwAccessibleParagraph::setCaretPosition( sal_Int32 nIndex )
1037{
1038 SolarMutexGuard aGuard;
1039
1040 ThrowIfDisposed();
1041
1042 // parameter checking
1043 sal_Int32 nLength = GetString().getLength();
1044 if ( ! IsValidPosition( nIndex, nLength ) )
1045 {
1046 throw lang::IndexOutOfBoundsException();
1047 }
1048
1049 bool bRet = false;
1050
1051 // get cursor shell
1052 SwCursorShell* pCursorShell = GetCursorShell();
1053 if( pCursorShell != nullptr )
1054 {
1055 // create pam for selection
1056 SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(GetFrame()));
1057 TextFrameIndex const nFrameIndex(GetPortionData().GetCoreViewPosition(nIndex));
1058 SwPosition aStartPos(pFrame->MapViewToModelPos(nFrameIndex));
1059 SwPaM aPaM( aStartPos );
1060
1061 // set PaM at cursor shell
1062 bRet = Select( aPaM );
1063 }
1064
1065 return bRet;
1066}
1067
1068sal_Unicode SwAccessibleParagraph::getCharacter( sal_Int32 nIndex )
1069{
1070 SolarMutexGuard aGuard;
1071
1072 ThrowIfDisposed();
1073
1074 OUString sText( GetString() );
1075
1076 // return character (if valid)
1077 if( !IsValidChar(nIndex, sText.getLength() ) )
1078 throw lang::IndexOutOfBoundsException();
1079
1080 return sText[nIndex];
1081}
1082
1083css::uno::Sequence< css::style::TabStop > SwAccessibleParagraph::GetCurrentTabStop( sal_Int32 nIndex )
1084{
1085 SolarMutexGuard aGuard;
1086
1087 ThrowIfDisposed();
1088
1089 /* #i12332# The position after the string needs special treatment.
1090 IsValidChar -> IsValidPosition
1091 */
1092 if( ! (IsValidPosition( nIndex, GetString().getLength() ) ) )
1093 throw lang::IndexOutOfBoundsException();
1094
1095 /* #i12332# */
1096 bool bBehindText = false;
1097 if ( nIndex == GetString().getLength() )
1098 bBehindText = true;
1099
1100 // get model position & prepare GetCharRect() arguments
1101 SwCursorMoveState aMoveState;
1102 aMoveState.m_bRealHeight = true;
1103 aMoveState.m_bRealWidth = true;
1104 SwSpecialPos aSpecialPos;
1105 SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(GetFrame()));
1106
1107 /* #i12332# FillSpecialPos does not accept nIndex ==
1108 GetString().getLength(). In that case nPos is set to the
1109 length of the string in the core. This way GetCharRect
1110 returns the rectangle for a cursor at the end of the
1111 paragraph. */
1112 const TextFrameIndex nPos = bBehindText
1113 ? TextFrameIndex(pFrame->GetText().getLength())
1114 : GetPortionData().FillSpecialPos(nIndex, aSpecialPos, aMoveState.m_pSpecialPos );
1115
1116 // call GetCharRect
1117 SwRect aCoreRect;
1118 SwPosition aPosition(pFrame->MapViewToModelPos(nPos));
1119 GetFrame()->GetCharRect( aCoreRect, aPosition, &aMoveState );
1120
1121 // already get the caret position
1122 css::uno::Sequence< css::style::TabStop > tabs;
1123 const sal_Int32 nStrLen = pFrame->GetText().getLength();
1124 if( nStrLen > 0 )
1125 {
1126 SwFrame* pTFrame = const_cast<SwFrame*>(GetFrame());
1127 tabs = pTFrame->GetTabStopInfo(aCoreRect.Left());
1128 }
1129
1130 if( tabs.hasElements() )
1131 {
1132 // translate core coordinates into accessibility coordinates
1133 vcl::Window *pWin = GetWindow();
1134 if (!pWin)
1135 {
1136 throw uno::RuntimeException("no Window", static_cast<cppu::OWeakObject*>(this));
1137 }
1138
1139 SwRect aTmpRect(0, 0, tabs[0].Position, 0);
1140
1141 tools::Rectangle aScreenRect( GetMap()->CoreToPixel( aTmpRect.SVRect() ));
1142 SwRect aFrameLogBounds( GetBounds( *(GetMap()) ) ); // twip rel to doc root
1143
1144 Point aFramePixPos( GetMap()->CoreToPixel( aFrameLogBounds.SVRect() ).TopLeft() );
1145 aScreenRect.Move( -aFramePixPos.X(), -aFramePixPos.Y() );
1146
1147 tabs[0].Position = aScreenRect.GetWidth();
1148 }
1149
1150 return tabs;
1151}
1152
1153namespace {
1154
1155struct IndexCompare
1156{
1157 const PropertyValue* pValues;
1158 explicit IndexCompare( const PropertyValue* pVals ) : pValues(pVals) {}
1159 bool operator() ( sal_Int32 a, sal_Int32 b ) const
1160 {
1161 return (pValues[a].Name < pValues[b].Name);
1162 }
1163};
1164
1165}
1166
1167OUString SwAccessibleParagraph::GetFieldTypeNameAtIndex(sal_Int32 nIndex)
1168{
1169 OUString strTypeName;
1170 SwFieldMgr aMgr;
1171 SwTextField* pTextField = nullptr;
1172 sal_Int32 nFieldIndex = GetPortionData().GetFieldIndex(nIndex);
1173 if (nFieldIndex >= 0)
1174 {
1175 SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(GetFrame()));
1176 sw::MergedAttrIter iter(*pFrame);
1177 while (SwTextAttr const*const pHt = iter.NextAttr())
1178 {
1179 if ((pHt->Which() == RES_TXTATR_FIELD
1180 || pHt->Which() == RES_TXTATR_ANNOTATION
1181 || pHt->Which() == RES_TXTATR_INPUTFIELD)
1182 && (nFieldIndex-- == 0))
1183 {
1184 pTextField = const_cast<SwTextField*>(
1185 static_txtattr_cast<SwTextField const*>(pHt));
1186 break;
1187 }
1188 else if (pHt->Which() == RES_TXTATR_REFMARK
1189 && (nFieldIndex-- == 0))
1190 {
1191 strTypeName = "set reference";
1192 }
1193 }
1194 }
1195 if (pTextField)
1196 {
1197 const SwField* pField = pTextField->GetFormatField().GetField();
1198 if (pField)
1199 {
1200 strTypeName = SwFieldType::GetTypeStr(pField->GetTypeId());
1201 const SwFieldIds nWhich = pField->GetTyp()->Which();
1202 OUString sEntry;
1203 sal_uInt32 subType = 0;
1204 switch (nWhich)
1205 {
1206 case SwFieldIds::DocStat:
1207 subType = static_cast<const SwDocStatField*>(pField)->GetSubType();
1208 break;
1209 case SwFieldIds::GetRef:
1210 {
1211 switch( pField->GetSubType() )
1212 {
1213 case REF_BOOKMARK:
1214 {
1215 const SwGetRefField* pRefField = dynamic_cast<const SwGetRefField*>(pField);
1216 if ( pRefField && pRefField->IsRefToHeadingCrossRefBookmark() )
1217 sEntry = "Headings";
1218 else if ( pRefField && pRefField->IsRefToNumItemCrossRefBookmark() )
1219 sEntry = "Numbered Paragraphs";
1220 else
1221 sEntry = "Bookmarks";
1222 }
1223 break;
1224 case REF_FOOTNOTE:
1225 sEntry = "Footnotes";
1226 break;
1227 case REF_ENDNOTE:
1228 sEntry = "Endnotes";
1229 break;
1230 case REF_SETREFATTR:
1231 sEntry = "Insert Reference";
1232 break;
1233 case REF_SEQUENCEFLD:
1234 sEntry = static_cast<const SwGetRefField*>(pField)->GetSetRefName();
1235 break;
1236 }
1237 //Get format string
1238 strTypeName = sEntry;
1239 // <pField->GetFormat() >= 0> is always true as <pField->GetFormat()> is unsigned
1240// if (pField->GetFormat() >= 0)
1241 {
1242 sEntry = aMgr.GetFormatStr( pField->GetTypeId(), pField->GetFormat() );
1243 if (sEntry.getLength() > 0)
1244 {
1245 strTypeName += "-" + sEntry;
1246 }
1247 }
1248 }
1249 break;
1250 case SwFieldIds::DateTime:
1251 subType = static_cast<const SwDateTimeField*>(pField)->GetSubType();
1252 break;
1253 case SwFieldIds::JumpEdit:
1254 {
1255 const sal_uInt32 nFormat= pField->GetFormat();
1256 const sal_uInt16 nSize = aMgr.GetFormatCount(pField->GetTypeId(), false);
1257 if (nFormat < nSize)
1258 {
1259 sEntry = aMgr.GetFormatStr(pField->GetTypeId(), nFormat);
1260 if (sEntry.getLength() > 0)
1261 {
1262 strTypeName += "-" + sEntry;
1263 }
1264 }
1265 }
1266 break;
1267 case SwFieldIds::ExtUser:
1268 subType = static_cast<const SwExtUserField*>(pField)->GetSubType();
1269 break;
1270 case SwFieldIds::HiddenText:
1271 case SwFieldIds::SetExp:
1272 {
1273 sEntry = pField->GetTyp()->GetName();
1274 if (sEntry.getLength() > 0)
1275 {
1276 strTypeName += "-" + sEntry;
1277 }
1278 }
1279 break;
1280 case SwFieldIds::DocInfo:
1281 subType = pField->GetSubType();
1282 subType &= 0x00ff;
1283 break;
1284 case SwFieldIds::RefPageSet:
1285 {
1286 const SwRefPageSetField* pRPld = static_cast<const SwRefPageSetField*>(pField);
1287 bool bOn = pRPld->IsOn();
1288 strTypeName += "-";
1289 if (bOn)
1290 strTypeName += "on";
1291 else
1292 strTypeName += "off";
1293 }
1294 break;
1295 case SwFieldIds::Author:
1296 {
1297 strTypeName += "-" + aMgr.GetFormatStr(pField->GetTypeId(), pField->GetFormat() & 0xff);
1298 }
1299 break;
1300 default: break;
1301 }
1302 if (subType > 0 || nWhich == SwFieldIds::DocInfo || nWhich == SwFieldIds::ExtUser || nWhich == SwFieldIds::DocStat)
1303 {
1304 std::vector<OUString> aLst;
1305 aMgr.GetSubTypes(pField->GetTypeId(), aLst);
1306 if (subType < aLst.size())
1307 sEntry = aLst[subType];
1308 if (sEntry.getLength() > 0)
1309 {
1310 if (nWhich == SwFieldIds::DocInfo)
1311 {
1312 strTypeName = sEntry;
1313 sal_uInt16 nSize = aMgr.GetFormatCount(pField->GetTypeId(), false);
1314 const sal_uInt16 nExSub = pField->GetSubType() & 0xff00;
1315 if (nSize > 0 && nExSub > 0)
1316 {
1317 //Get extra subtype string
1318 strTypeName += "-";
1319 sEntry = aMgr.GetFormatStr(pField->GetTypeId(), nExSub/0x0100-1);
1320 strTypeName += sEntry;
1321 }
1322 }
1323 else
1324 {
1325 strTypeName += "-" + sEntry;
1326 }
1327 }
1328 }
1329 }
1330 }
1331 return strTypeName;
1332}
1333
1334// #i63870# - re-implement method on behalf of methods
1335// <_getDefaultAttributesImpl(..)> and <_getRunAttributesImpl(..)>
1336uno::Sequence<PropertyValue> SwAccessibleParagraph::getCharacterAttributes(
1337 sal_Int32 nIndex,
1338 const uno::Sequence< OUString >& aRequestedAttributes )
1339{
1340
1341 SolarMutexGuard aGuard;
1342
1343 ThrowIfDisposed();
1344
1345 const OUString& rText = GetString();
1346
1347 if (!IsValidPosition(nIndex, rText.getLength()))
1348 throw lang::IndexOutOfBoundsException();
1349
1350 bool bSupplementalMode = false;
1351 uno::Sequence< OUString > aNames = aRequestedAttributes;
1352 if (!aNames.hasElements())
1353 {
1354 bSupplementalMode = true;
1355 aNames = getAttributeNames();
1356 }
1357 // retrieve default character attributes
1358 tAccParaPropValMap aDefAttrSeq;
1359 _getDefaultAttributesImpl( aNames, aDefAttrSeq, true );
1360
1361 // retrieved run character attributes
1362 tAccParaPropValMap aRunAttrSeq;
1363 _getRunAttributesImpl( nIndex, aNames, aRunAttrSeq );
1364
1365 // merge default and run attributes
1366 std::vector< PropertyValue > aValues( aDefAttrSeq.size() );
1367 sal_Int32 i = 0;
1368 for ( const auto& rDefEntry : aDefAttrSeq )
1369 {
1370 tAccParaPropValMap::const_iterator aRunIter =
1371 aRunAttrSeq.find( rDefEntry.first );
1372 if ( aRunIter != aRunAttrSeq.end() )
1373 {
1374 aValues[i] = aRunIter->second;
1375 }
1376 else
1377 {
1378 aValues[i] = rDefEntry.second;
1379 }
1380 ++i;
1381 }
1382 if( bSupplementalMode )
1383 {
1384 uno::Sequence< OUString > aSupplementalNames = aRequestedAttributes;
1385 if (!aSupplementalNames.hasElements())
1386 aSupplementalNames = getSupplementalAttributeNames();
1387
1388 tAccParaPropValMap aSupplementalAttrSeq;
1389 _getSupplementalAttributesImpl( aSupplementalNames, aSupplementalAttrSeq );
1390
1391 aValues.resize( aValues.size() + aSupplementalAttrSeq.size() );
1392
1393 for ( const auto& rSupplementalEntry : aSupplementalAttrSeq )
1394 {
1395 aValues[i] = rSupplementalEntry.second;
1396 ++i;
1397 }
1398
1399 _correctValues( nIndex, aValues );
1400
1401 aValues.emplace_back();
1402
1403 OUString strTypeName = GetFieldTypeNameAtIndex(nIndex);
1404 if (!strTypeName.isEmpty())
1405 {
1406 aValues.emplace_back();
1407 PropertyValue& rValueFT = aValues.back();
1408 rValueFT.Name = "FieldType";
1409 rValueFT.Value <<= strTypeName.toAsciiLowerCase();
1410 rValueFT.Handle = -1;
1411 rValueFT.State = PropertyState_DIRECT_VALUE;
1412 }
1413
1414 //sort property values
1415 // build sorted index array
1416 sal_Int32 nLength = aValues.size();
1417 std::vector<sal_Int32> aIndices;
1418 aIndices.reserve(nLength);
1419 for (i = 0; i < nLength; ++i)
1420 aIndices.push_back(i);
1421 std::sort(aIndices.begin(), aIndices.end(), IndexCompare(aValues.data()));
1422 // create sorted sequences according to index array
1423 uno::Sequence<PropertyValue> aNewValues( nLength );
1424 PropertyValue* pNewValues = aNewValues.getArray();
1425 for (i = 0; i < nLength; ++i)
1426 {
1427 pNewValues[i] = aValues[aIndices[i]];
1428 }
1429 return aNewValues;
1430 }
1431
1432 return comphelper::containerToSequence(aValues);
1433}
1434
1435static void SetPutRecursive(SfxItemSet &targetSet, const SfxItemSet &sourceSet)
1436{
1437 const SfxItemSet *const pParentSet = sourceSet.GetParent();
1438 if (pParentSet)
1439 SetPutRecursive(targetSet, *pParentSet);
1440 targetSet.Put(sourceSet);
1441}
1442
1443// #i63870#
1444void SwAccessibleParagraph::_getDefaultAttributesImpl(
1445 const uno::Sequence< OUString >& aRequestedAttributes,
1446 tAccParaPropValMap& rDefAttrSeq,
1447 const bool bOnlyCharAttrs )
1448{
1449 // retrieve default attributes
1450 SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(GetFrame()));
1451 const SwTextNode *const pTextNode(pFrame->GetTextNodeForParaProps());
1452 std::unique_ptr<SfxItemSet> pSet;
1453 if ( !bOnlyCharAttrs )
1454 {
1455 pSet.reset( new SfxItemSet( const_cast<SwAttrPool&>(pTextNode->GetDoc().GetAttrPool()),
1456 svl::Items<RES_CHRATR_BEGIN, RES_CHRATR_END - 1,
1457 RES_PARATR_BEGIN, RES_PARATR_END - 1,
1458 RES_FRMATR_BEGIN, RES_FRMATR_END - 1>{} ) );
1459 }
1460 else
1461 {
1462 pSet.reset( new SfxItemSet( const_cast<SwAttrPool&>(pTextNode->GetDoc().GetAttrPool()),
1463 svl::Items<RES_CHRATR_BEGIN, RES_CHRATR_END - 1>{} ) );
1464 }
1465 // #i82637# - From the perspective of the a11y API the default character
1466 // attributes are the character attributes, which are set at the paragraph style
1467 // of the paragraph. The character attributes set at the automatic paragraph
1468 // style of the paragraph are treated as run attributes.
1469 // pTextNode->SwContentNode::GetAttr( *pSet );
1470 // get default paragraph attributes, if needed, and merge these into <pSet>
1471 if ( !bOnlyCharAttrs )
1472 {
1473 SfxItemSet aParaSet( const_cast<SwAttrPool&>(pTextNode->GetDoc().GetAttrPool()),
1474 svl::Items<RES_PARATR_BEGIN, RES_PARATR_END - 1,
1475 RES_FRMATR_BEGIN, RES_FRMATR_END - 1>{} );
1476 pTextNode->SwContentNode::GetAttr( aParaSet );
1477 pSet->Put( aParaSet );
1478 }
1479 // get default character attributes and merge these into <pSet>
1480 OSL_ENSURE( pTextNode->GetTextColl(),do { if (true && (!(pTextNode->GetTextColl()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "1481" ": "), "%s", "<SwAccessibleParagraph::_getDefaultAttributesImpl(..)> - missing paragraph style. Serious defect!"
); } } while (false)
1481 "<SwAccessibleParagraph::_getDefaultAttributesImpl(..)> - missing paragraph style. Serious defect!" )do { if (true && (!(pTextNode->GetTextColl()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "1481" ": "), "%s", "<SwAccessibleParagraph::_getDefaultAttributesImpl(..)> - missing paragraph style. Serious defect!"
); } } while (false)
;
1482 if ( pTextNode->GetTextColl() )
1483 {
1484 SfxItemSet aCharSet( const_cast<SwAttrPool&>(pTextNode->GetDoc().GetAttrPool()),
1485 svl::Items<RES_CHRATR_BEGIN, RES_CHRATR_END - 1>{} );
1486 SetPutRecursive( aCharSet, pTextNode->GetTextColl()->GetAttrSet() );
1487 pSet->Put( aCharSet );
1488 }
1489
1490 // build-up sequence containing the run attributes <rDefAttrSeq>
1491 tAccParaPropValMap aDefAttrSeq;
1492 {
1493 const SfxItemPropertyMap& rPropMap =
1494 aSwMapProvider.GetPropertySet( PROPERTY_MAP_TEXT_CURSOR0 )->getPropertyMap();
1495 PropertyEntryVector_t aPropertyEntries = rPropMap.getPropertyEntries();
1496 for ( const auto& rProp : aPropertyEntries )
1497 {
1498 const SfxPoolItem* pItem = pSet->GetItem( rProp.nWID );
1499 if ( pItem )
1500 {
1501 uno::Any aVal;
1502 pItem->QueryValue( aVal, rProp.nMemberId );
1503
1504 PropertyValue rPropVal;
1505 rPropVal.Name = rProp.sName;
1506 rPropVal.Value = aVal;
1507 rPropVal.Handle = -1;
1508 rPropVal.State = beans::PropertyState_DEFAULT_VALUE;
1509
1510 aDefAttrSeq[rPropVal.Name] = rPropVal;
1511 }
1512 }
1513
1514 // #i72800#
1515 // add property value entry for the paragraph style
1516 if ( !bOnlyCharAttrs && pTextNode->GetTextColl() )
1517 {
1518 if ( aDefAttrSeq.find( UNO_NAME_PARA_STYLE_NAME"ParaStyleName" ) == aDefAttrSeq.end() )
1519 {
1520 PropertyValue rPropVal;
1521 rPropVal.Name = UNO_NAME_PARA_STYLE_NAME"ParaStyleName";
1522 uno::Any aVal( uno::makeAny( pTextNode->GetTextColl()->GetName() ) );
1523 rPropVal.Value = aVal;
1524 rPropVal.Handle = -1;
1525 rPropVal.State = beans::PropertyState_DEFAULT_VALUE;
1526
1527 aDefAttrSeq[rPropVal.Name] = rPropVal;
1528 }
1529 }
1530
1531 // #i73371#
1532 // resolve value text::WritingMode2::PAGE of property value entry WritingMode
1533 if ( !bOnlyCharAttrs && GetFrame() )
1534 {
1535 tAccParaPropValMap::iterator aIter = aDefAttrSeq.find( UNO_NAME_WRITING_MODE"WritingMode" );
1536 if ( aIter != aDefAttrSeq.end() )
1537 {
1538 PropertyValue rPropVal( aIter->second );
1539 sal_Int16 nVal = rPropVal.Value.get<sal_Int16>();
1540 if ( nVal == text::WritingMode2::PAGE )
1541 {
1542 const SwFrame* pUpperFrame( GetFrame()->GetUpper() );
1543 while ( pUpperFrame )
1544 {
1545 if ( pUpperFrame->GetType() &
1546 ( SwFrameType::Page | SwFrameType::Fly | SwFrameType::Section | SwFrameType::Tab | SwFrameType::Cell ) )
1547 {
1548 if ( pUpperFrame->IsVertical() )
1549 {
1550 nVal = text::WritingMode2::TB_RL;
1551 }
1552 else if ( pUpperFrame->IsRightToLeft() )
1553 {
1554 nVal = text::WritingMode2::RL_TB;
1555 }
1556 else
1557 {
1558 nVal = text::WritingMode2::LR_TB;
1559 }
1560 rPropVal.Value <<= nVal;
1561 aDefAttrSeq[rPropVal.Name] = rPropVal;
1562 break;
1563 }
1564
1565 if ( const SwFlyFrame* pFlyFrame = dynamic_cast<const SwFlyFrame*>(pUpperFrame) )
1566 {
1567 pUpperFrame = pFlyFrame->GetAnchorFrame();
1568 }
1569 else
1570 {
1571 pUpperFrame = pUpperFrame->GetUpper();
1572 }
1573 }
1574 }
1575 }
1576 }
1577 }
1578
1579 if ( !aRequestedAttributes.hasElements() )
1580 {
1581 rDefAttrSeq = aDefAttrSeq;
1582 }
1583 else
1584 {
1585 for( const OUString& rReqAttr : aRequestedAttributes )
1586 {
1587 tAccParaPropValMap::const_iterator const aIter = aDefAttrSeq.find( rReqAttr );
1588 if ( aIter != aDefAttrSeq.end() )
1589 {
1590 rDefAttrSeq[ aIter->first ] = aIter->second;
1591 }
1592 }
1593 }
1594}
1595
1596uno::Sequence< PropertyValue > SwAccessibleParagraph::getDefaultAttributes(
1597 const uno::Sequence< OUString >& aRequestedAttributes )
1598{
1599 SolarMutexGuard aGuard;
1600
1601 ThrowIfDisposed();
1602
1603 tAccParaPropValMap aDefAttrSeq;
1604 _getDefaultAttributesImpl( aRequestedAttributes, aDefAttrSeq );
1605
1606 // #i92233#
1607 static const char sMMToPixelRatio[] = "MMToPixelRatio";
1608 bool bProvideMMToPixelRatio( !aRequestedAttributes.hasElements() ||
1609 (comphelper::findValue(aRequestedAttributes, sMMToPixelRatio) != -1) );
1610
1611 uno::Sequence< PropertyValue > aValues( aDefAttrSeq.size() +
1612 ( bProvideMMToPixelRatio ? 1 : 0 ) );
1613 std::transform(aDefAttrSeq.begin(), aDefAttrSeq.end(), aValues.begin(),
1614 [](const auto& rEntry) -> PropertyValue { return rEntry.second; });
1615
1616 // #i92233#
1617 if ( bProvideMMToPixelRatio )
1618 {
1619 PropertyValue rPropVal;
1620 rPropVal.Name = sMMToPixelRatio;
1621 const Size a100thMMSize( 1000, 1000 );
1622 const Size aPixelSize = GetMap()->LogicToPixel( a100thMMSize );
1623 const float fRatio = (static_cast<float>(a100thMMSize.Width())/100)/aPixelSize.Width();
1624 rPropVal.Value <<= fRatio;
1625 rPropVal.Handle = -1;
1626 rPropVal.State = beans::PropertyState_DEFAULT_VALUE;
1627 aValues[ aValues.getLength() - 1 ] = rPropVal;
1628 }
1629
1630 return aValues;
1631}
1632
1633void SwAccessibleParagraph::_getRunAttributesImpl(
1634 const sal_Int32 nIndex,
1635 const uno::Sequence< OUString >& aRequestedAttributes,
1636 tAccParaPropValMap& rRunAttrSeq )
1637{
1638 // create PaM for character at position <nIndex>
1639 std::unique_ptr<SwPaM> pPaM;
1640 const TextFrameIndex nCorePos(GetPortionData().GetCoreViewPosition(nIndex));
1641 SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(GetFrame()));
1642 SwPosition const aModelPos(pFrame->MapViewToModelPos(nCorePos));
1643 SwTextNode *const pTextNode(aModelPos.nNode.GetNode().GetTextNode());
1644 {
1645 SwPosition const aEndPos(*pTextNode,
1646 aModelPos.nContent.GetIndex() == pTextNode->Len()
1647 ? pTextNode->Len() // ???
1648 : aModelPos.nContent.GetIndex() + 1);
1649 pPaM.reset(new SwPaM(aModelPos, aEndPos));
1650 }
1651
1652 // retrieve character attributes for the created PaM <pPaM>
1653 SfxItemSet aSet( pPaM->GetDoc().GetAttrPool(),
1654 svl::Items<RES_CHRATR_BEGIN, RES_CHRATR_END -1>{} );
1655 // #i82637#
1656 // From the perspective of the a11y API the character attributes, which
1657 // are set at the automatic paragraph style of the paragraph, are treated
1658 // as run attributes.
1659 // SwXTextCursor::GetCursorAttr( *pPaM, aSet, sal_True, sal_True );
1660 // get character attributes from automatic paragraph style and merge these into <aSet>
1661 {
1662 if ( pTextNode->HasSwAttrSet() )
1663 {
1664 SfxItemSet aAutomaticParaStyleCharAttrs( pPaM->GetDoc().GetAttrPool(),
1665 svl::Items<RES_CHRATR_BEGIN, RES_CHRATR_END -1>{} );
1666 aAutomaticParaStyleCharAttrs.Put( *(pTextNode->GetpSwAttrSet()), false );
1667 aSet.Put( aAutomaticParaStyleCharAttrs );
1668 }
1669 }
1670 // get character attributes at <pPaM> and merge these into <aSet>
1671 {
1672 SfxItemSet aCharAttrsAtPaM( pPaM->GetDoc().GetAttrPool(),
1673 svl::Items<RES_CHRATR_BEGIN, RES_CHRATR_END -1>{} );
1674 SwUnoCursorHelper::GetCursorAttr(*pPaM, aCharAttrsAtPaM, true);
1675 aSet.Put( aCharAttrsAtPaM );
1676 }
1677
1678 // build-up sequence containing the run attributes <rRunAttrSeq>
1679 {
1680 tAccParaPropValMap aRunAttrSeq;
1681 {
1682 tAccParaPropValMap aDefAttrSeq;
1683 uno::Sequence< OUString > aDummy;
1684 _getDefaultAttributesImpl( aDummy, aDefAttrSeq, true ); // #i82637#
1685
1686 const SfxItemPropertyMap& rPropMap =
1687 aSwMapProvider.GetPropertySet( PROPERTY_MAP_TEXT_CURSOR0 )->getPropertyMap();
1688 PropertyEntryVector_t aPropertyEntries = rPropMap.getPropertyEntries();
1689 for ( const auto& rProp : aPropertyEntries )
1690 {
1691 const SfxPoolItem* pItem( nullptr );
1692 // #i82637# - Found character attributes, whose value equals the value of
1693 // the corresponding default character attributes, are excluded.
1694 if ( aSet.GetItemState( rProp.nWID, true, &pItem ) == SfxItemState::SET )
1695 {
1696 uno::Any aVal;
1697 pItem->QueryValue( aVal, rProp.nMemberId );
1698
1699 PropertyValue rPropVal;
1700 rPropVal.Name = rProp.sName;
1701 rPropVal.Value = aVal;
1702 rPropVal.Handle = -1;
1703 rPropVal.State = PropertyState_DIRECT_VALUE;
1704
1705 tAccParaPropValMap::const_iterator aDefIter =
1706 aDefAttrSeq.find( rPropVal.Name );
1707 if ( aDefIter == aDefAttrSeq.end() ||
1708 rPropVal.Value != aDefIter->second.Value )
1709 {
1710 aRunAttrSeq[rPropVal.Name] = rPropVal;
1711 }
1712 }
1713 }
1714 }
1715
1716 if ( !aRequestedAttributes.hasElements() )
1717 {
1718 rRunAttrSeq = aRunAttrSeq;
1719 }
1720 else
1721 {
1722 for( const OUString& rReqAttr : aRequestedAttributes )
1723 {
1724 tAccParaPropValMap::iterator aIter = aRunAttrSeq.find( rReqAttr );
1725 if ( aIter != aRunAttrSeq.end() )
1726 {
1727 rRunAttrSeq[ (*aIter).first ] = (*aIter).second;
1728 }
1729 }
1730 }
1731 }
1732}
1733
1734uno::Sequence< PropertyValue > SwAccessibleParagraph::getRunAttributes(
1735 sal_Int32 nIndex,
1736 const uno::Sequence< OUString >& aRequestedAttributes )
1737{
1738 SolarMutexGuard aGuard;
1739
1740 ThrowIfDisposed();
1741
1742 {
1743 const OUString& rText = GetString();
1744 if (!IsValidPosition(nIndex, rText.getLength()))
1745 {
1746 throw lang::IndexOutOfBoundsException();
1747 }
1748 }
1749
1750 tAccParaPropValMap aRunAttrSeq;
1751 _getRunAttributesImpl( nIndex, aRequestedAttributes, aRunAttrSeq );
1752
1753 return comphelper::mapValuesToSequence( aRunAttrSeq );
1754}
1755
1756void SwAccessibleParagraph::_getSupplementalAttributesImpl(
1757 const uno::Sequence< OUString >& aRequestedAttributes,
1758 tAccParaPropValMap& rSupplementalAttrSeq )
1759{
1760 SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(GetFrame()));
1761 const SwTextNode *const pTextNode(pFrame->GetTextNodeForParaProps());
1762 std::unique_ptr<SfxItemSet> pSet;
1763 pSet.reset(
1764 new SfxItemSet(
1765 const_cast<SwAttrPool&>(pTextNode->GetDoc().GetAttrPool()),
1766 svl::Items<
1767 RES_PARATR_LINESPACING, RES_PARATR_ADJUST,
1768 RES_PARATR_TABSTOP, RES_PARATR_TABSTOP,
1769 RES_PARATR_NUMRULE, RES_PARATR_NUMRULE,
1770 RES_PARATR_LIST_BEGIN, RES_PARATR_LIST_END - 1,
1771 RES_LR_SPACE, RES_UL_SPACE>{}));
1772
1773 if ( pTextNode->HasBullet() || pTextNode->HasNumber() )
1774 {
1775 pSet->Put( pTextNode->GetAttr(RES_PARATR_LIST_LEVEL) );
1776 }
1777 pSet->Put( pTextNode->SwContentNode::GetAttr(RES_UL_SPACE) );
1778 pSet->Put( pTextNode->SwContentNode::GetAttr(RES_LR_SPACE) );
1779 pSet->Put( pTextNode->SwContentNode::GetAttr(RES_PARATR_ADJUST) );
1780
1781 tAccParaPropValMap aSupplementalAttrSeq;
1782 {
1783 const SfxItemPropertyMapEntry* pPropMap(
1784 aSwMapProvider.GetPropertyMapEntries( PROPERTY_MAP_ACCESSIBILITY_TEXT_ATTRIBUTE99 ) );
1785 while ( !pPropMap->aName.empty() )
1786 {
1787 const SfxPoolItem* pItem = pSet->GetItem( pPropMap->nWID );
1788 if ( pItem )
1789 {
1790 uno::Any aVal;
1791 pItem->QueryValue( aVal, pPropMap->nMemberId );
1792
1793 PropertyValue rPropVal;
1794 rPropVal.Name = pPropMap->aName;
1795 rPropVal.Value = aVal;
1796 rPropVal.Handle = -1;
1797 rPropVal.State = beans::PropertyState_DEFAULT_VALUE;
1798
1799 aSupplementalAttrSeq[rPropVal.Name] = rPropVal;
1800 }
1801
1802 ++pPropMap;
1803 }
1804 }
1805
1806 for( const OUString& rSupplementalAttr : aRequestedAttributes )
1807 {
1808 tAccParaPropValMap::const_iterator const aIter = aSupplementalAttrSeq.find( rSupplementalAttr );
1809 if ( aIter != aSupplementalAttrSeq.end() )
1810 {
1811 rSupplementalAttrSeq[ aIter->first ] = aIter->second;
1812 }
1813 }
1814}
1815
1816void SwAccessibleParagraph::_correctValues( const sal_Int32 nIndex,
1817 std::vector< PropertyValue >& rValues)
1818{
1819 PropertyValue ChangeAttr, ChangeAttrColor;
1820
1821 const SwRangeRedline* pRedline = GetRedlineAtIndex();
1822 if ( pRedline )
1823 {
1824
1825 const SwModuleOptions *pOpt = SW_MOD()( static_cast<SwModule*>(SfxApplication::GetModule(SfxToolsModule
::Writer)))
->GetModuleConfig();
1826 AuthorCharAttr aChangeAttr;
1827 if ( pOpt )
1828 {
1829 switch( pRedline->GetType())
1830 {
1831 case RedlineType::Insert:
1832 aChangeAttr = pOpt->GetInsertAuthorAttr();
1833 break;
1834 case RedlineType::Delete:
1835 aChangeAttr = pOpt->GetDeletedAuthorAttr();
1836 break;
1837 case RedlineType::Format:
1838 aChangeAttr = pOpt->GetFormatAuthorAttr();
1839 break;
1840 default: break;
1841 }
1842 }
1843 switch( aChangeAttr.m_nItemId )
1844 {
1845 case SID_ATTR_CHAR_WEIGHT( 10000 + 9 ):
1846 ChangeAttr.Name = UNO_NAME_CHAR_WEIGHT"CharWeight";
1847 ChangeAttr.Value <<= awt::FontWeight::BOLD;
1848 break;
1849 case SID_ATTR_CHAR_POSTURE( 10000 + 8 ):
1850 ChangeAttr.Name = UNO_NAME_CHAR_POSTURE"CharPosture";
1851 ChangeAttr.Value <<= awt::FontSlant_ITALIC; //char posture
1852 break;
1853 case SID_ATTR_CHAR_STRIKEOUT( 10000 + 13 ):
1854 ChangeAttr.Name = UNO_NAME_CHAR_STRIKEOUT"CharStrikeout";
1855 ChangeAttr.Value <<= awt::FontStrikeout::SINGLE; //char strikeout
1856 break;
1857 case SID_ATTR_CHAR_UNDERLINE( 10000 + 14 ):
1858 ChangeAttr.Name = UNO_NAME_CHAR_UNDERLINE"CharUnderline";
1859 ChangeAttr.Value <<= aChangeAttr.m_nAttr; //underline line
1860 break;
1861 }
1862 if( aChangeAttr.m_nColor != COL_NONE_COLOR::Color(0x80, 0xFF, 0xFF, 0xFF) )
1863 {
1864 if( aChangeAttr.m_nItemId == SID_ATTR_BRUSH( 10000 + 1 ) )
1865 {
1866 ChangeAttrColor.Name = UNO_NAME_CHAR_BACK_COLOR"CharBackColor";
1867 if( aChangeAttr.m_nColor == COL_TRANSPARENT )//char backcolor
1868 ChangeAttrColor.Value <<= COL_BLUE;
1869 else
1870 ChangeAttrColor.Value <<= aChangeAttr.m_nColor;
1871 }
1872 else
1873 {
1874 ChangeAttrColor.Name = UNO_NAME_CHAR_COLOR"CharColor";
1875 if( aChangeAttr.m_nColor == COL_TRANSPARENT )//char color
1876 ChangeAttrColor.Value <<= COL_BLUE;
1877 else
1878 ChangeAttrColor.Value <<= aChangeAttr.m_nColor;
1879 }
1880 }
1881 }
1882
1883 // sw_redlinehide: this function only needs SwWrongList for 1 character,
1884 // and the end is excluded by InWrongWord(),
1885 // so it ought to work to just pick the wrong-list/node that contains
1886 // the character following the given nIndex
1887 SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(GetFrame()));
1888 TextFrameIndex const nCorePos(GetPortionData().GetCoreViewPosition(nIndex));
1889 std::pair<SwTextNode*, sal_Int32> pos(pFrame->MapViewToModel(nCorePos));
1890 if (pos.first->Len() == pos.second
1891 && nCorePos != TextFrameIndex(pFrame->GetText().getLength()))
1892 {
1893 pos = pFrame->MapViewToModel(nCorePos + TextFrameIndex(1)); // try this one instead
1894 assert(pos.first->Len() != pos.second)(static_cast <bool> (pos.first->Len() != pos.second)
? void (0) : __assert_fail ("pos.first->Len() != pos.second"
, "/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
, 1894, __extension__ __PRETTY_FUNCTION__))
;
1895 }
1896 const SwTextNode *const pTextNode(pos.first);
1897
1898 sal_Int32 nValues = rValues.size();
1899 for (sal_Int32 i = 0; i < nValues; ++i)
1900 {
1901 PropertyValue& rValue = rValues[i];
1902
1903 if (rValue.Name == ChangeAttr.Name )
1904 {
1905 rValue.Value = ChangeAttr.Value;
1906 continue;
1907 }
1908
1909 if (rValue.Name == ChangeAttrColor.Name )
1910 {
1911 rValue.Value = ChangeAttrColor.Value;
1912 continue;
1913 }
1914
1915 //back color
1916 if (rValue.Name == UNO_NAME_CHAR_BACK_COLOR"CharBackColor")
1917 {
1918 uno::Any &anyChar = rValue.Value;
1919 sal_uInt32 crBack = static_cast<sal_uInt32>( reinterpret_cast<sal_uIntPtr>(anyChar.pReserved));
1920 if (COL_AUTO == Color(crBack))
1921 {
1922 uno::Reference<XAccessibleComponent> xComponent(this);
1923 if (xComponent.is())
1924 {
1925 crBack = static_cast<sal_uInt32>(xComponent->getBackground());
1926 }
1927 rValue.Value <<= crBack;
1928 }
1929 continue;
1930 }
1931
1932 //char color
1933 if (rValue.Name == UNO_NAME_CHAR_COLOR"CharColor")
1934 {
1935 if( GetPortionData().IsInGrayPortion( nIndex ) )
1936 rValue.Value <<= SwViewOption::GetFieldShadingsColor();
1937 uno::Any &anyChar = rValue.Value;
1938 sal_uInt32 crChar = static_cast<sal_uInt32>( reinterpret_cast<sal_uIntPtr>(anyChar.pReserved));
1939
1940 if( COL_AUTO == Color(crChar) )
1941 {
1942 uno::Reference<XAccessibleComponent> xComponent(this);
1943 if (xComponent.is())
1944 {
1945 Color cr(xComponent->getBackground());
1946 crChar = sal_uInt32(cr.IsDark() ? COL_WHITE : COL_BLACK);
1947 rValue.Value <<= crChar;
1948 }
1949 }
1950 continue;
1951 }
1952
1953 // UnderLine
1954 if (rValue.Name == UNO_NAME_CHAR_UNDERLINE"CharUnderline")
1955 {
1956 //misspelled word
1957 SwCursorShell* pCursorShell = GetCursorShell();
1958 if( pCursorShell != nullptr && pCursorShell->GetViewOptions() && pCursorShell->GetViewOptions()->IsOnlineSpell())
1959 {
1960 const SwWrongList* pWrongList = pTextNode->GetWrong();
1961 if( nullptr != pWrongList )
1962 {
1963 sal_Int32 nBegin = pos.second;
1964 sal_Int32 nLen = 1;
1965 if (pWrongList->InWrongWord(nBegin, nLen) && !pTextNode->IsSymbolAt(nBegin))
1966 {
1967 rValue.Value <<= sal_uInt16(LINESTYLE_WAVE);
1968 }
1969 }
1970 }
1971 continue;
1972 }
1973
1974 // UnderLineColor
1975 if (rValue.Name == UNO_NAME_CHAR_UNDERLINE_COLOR"CharUnderlineColor")
1976 {
1977 //misspelled word
1978 SwCursorShell* pCursorShell = GetCursorShell();
1979 if( pCursorShell != nullptr && pCursorShell->GetViewOptions() && pCursorShell->GetViewOptions()->IsOnlineSpell())
1980 {
1981 const SwWrongList* pWrongList = pTextNode->GetWrong();
1982 if( nullptr != pWrongList )
1983 {
1984 sal_Int32 nBegin = pos.second;
1985 sal_Int32 nLen = 1;
1986 if (pWrongList->InWrongWord(nBegin, nLen) && !pTextNode->IsSymbolAt(nBegin))
1987 {
1988 rValue.Value <<= sal_Int32(0x00ff0000);
1989 continue;
1990 }
1991 }
1992 }
1993
1994 uno::Any &anyChar = rValue.Value;
1995 sal_uInt32 crUnderline = static_cast<sal_uInt32>( reinterpret_cast<sal_uIntPtr>(anyChar.pReserved));
1996 if ( COL_AUTO == Color(crUnderline) )
1997 {
1998 uno::Reference<XAccessibleComponent> xComponent(this);
1999 if (xComponent.is())
2000 {
2001 Color cr(xComponent->getBackground());
2002 crUnderline = sal_uInt32(cr.IsDark() ? COL_WHITE : COL_BLACK);
2003 rValue.Value <<= crUnderline;
2004 }
2005 }
2006
2007 continue;
2008 }
2009
2010 //tab stop
2011 if (rValue.Name == UNO_NAME_TABSTOPS"ParaTabStops")
2012 {
2013 css::uno::Sequence< css::style::TabStop > tabs = GetCurrentTabStop( nIndex );
2014 if( !tabs.hasElements() )
2015 {
2016 tabs.realloc(1);
2017 css::style::TabStop ts;
2018 css::awt::Rectangle rc0 = getCharacterBounds(0);
2019 css::awt::Rectangle rc1 = getCharacterBounds(nIndex);
2020 if( rc1.X - rc0.X >= 48 )
2021 ts.Position = (rc1.X - rc0.X) - (rc1.X - rc0.X - 48)% 47 + 47;
2022 else
2023 ts.Position = 48;
2024 ts.DecimalChar = ' ';
2025 ts.FillChar = ' ';
2026 ts.Alignment = css::style::TabAlign_LEFT;
2027 tabs[0] = ts;
2028 }
2029 rValue.Value <<= tabs;
2030 continue;
2031 }
2032
2033 //footnote & endnote
2034 if (rValue.Name == UNO_NAME_CHAR_ESCAPEMENT"CharEscapement")
2035 {
2036 if ( GetPortionData().IsIndexInFootnode(nIndex) )
2037 {
2038 rValue.Value <<= sal_Int32(101);
2039 }
2040 continue;
2041 }
2042 }
2043}
2044
2045awt::Rectangle SwAccessibleParagraph::getCharacterBounds(
2046 sal_Int32 nIndex )
2047{
2048 SolarMutexGuard aGuard;
2049
2050 ThrowIfDisposed();
2051
2052 // #i12332# The position after the string needs special treatment.
2053 // IsValidChar -> IsValidPosition
2054 if( ! (IsValidPosition( nIndex, GetString().getLength() ) ) )
2055 throw lang::IndexOutOfBoundsException();
2056
2057 // #i12332#
2058 bool bBehindText = false;
2059 if ( nIndex == GetString().getLength() )
2060 bBehindText = true;
2061
2062 // get model position & prepare GetCharRect() arguments
2063 SwCursorMoveState aMoveState;
2064 aMoveState.m_bRealHeight = true;
2065 aMoveState.m_bRealWidth = true;
2066 SwSpecialPos aSpecialPos;
2067 SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(GetFrame()));
2068
2069 /** #i12332# FillSpecialPos does not accept nIndex ==
2070 GetString().getLength(). In that case nPos is set to the
2071 length of the string in the core. This way GetCharRect
2072 returns the rectangle for a cursor at the end of the
2073 paragraph. */
2074 const TextFrameIndex nPos = bBehindText
2075 ? TextFrameIndex(pFrame->GetText().getLength())
2076 : GetPortionData().FillSpecialPos(nIndex, aSpecialPos, aMoveState.m_pSpecialPos );
2077
2078 // call GetCharRect
2079 SwRect aCoreRect;
2080 SwPosition aPosition(pFrame->MapViewToModelPos(nPos));
2081 GetFrame()->GetCharRect( aCoreRect, aPosition, &aMoveState );
2082
2083 // translate core coordinates into accessibility coordinates
2084 vcl::Window *pWin = GetWindow();
2085 if (!pWin)
2086 {
2087 throw uno::RuntimeException("no Window", static_cast<cppu::OWeakObject*>(this));
2088 }
2089
2090 tools::Rectangle aScreenRect( GetMap()->CoreToPixel( aCoreRect.SVRect() ));
2091 SwRect aFrameLogBounds( GetBounds( *(GetMap()) ) ); // twip rel to doc root
2092
2093 Point aFramePixPos( GetMap()->CoreToPixel( aFrameLogBounds.SVRect() ).TopLeft() );
2094 aScreenRect.Move( -aFramePixPos.getX(), -aFramePixPos.getY() );
2095
2096 // convert into AWT Rectangle
2097 return awt::Rectangle(
2098 aScreenRect.Left(), aScreenRect.Top(),
2099 aScreenRect.GetWidth(), aScreenRect.GetHeight() );
2100}
2101
2102sal_Int32 SwAccessibleParagraph::getCharacterCount()
2103{
2104 SolarMutexGuard aGuard;
2105
2106 ThrowIfDisposed();
2107
2108 return GetString().getLength();
2109}
2110
2111sal_Int32 SwAccessibleParagraph::getIndexAtPoint( const awt::Point& rPoint )
2112{
2113 SolarMutexGuard aGuard;
2114
2115 ThrowIfDisposed();
2116
2117 // construct Point (translate into layout coordinates)
2118 vcl::Window *pWin = GetWindow();
2119 if (!pWin)
2120 {
2121 throw uno::RuntimeException("no Window", static_cast<cppu::OWeakObject*>(this));
2122 }
2123 Point aPoint( rPoint.X, rPoint.Y );
2124 SwRect aLogBounds( GetBounds( *(GetMap()), GetFrame() ) ); // twip rel to doc root
2125 Point aPixPos( GetMap()->CoreToPixel( aLogBounds.SVRect() ).TopLeft() );
2126 aPoint.setX(aPoint.getX() + aPixPos.getX());
2127 aPoint.setY(aPoint.getY() + aPixPos.getY());
2128 Point aCorePoint( GetMap()->PixelToCore( aPoint ) );
2129 if( !aLogBounds.IsInside( aCorePoint ) )
2130 {
2131 // #i12332# rPoint is may also be in rectangle returned by
2132 // getCharacterBounds(getCharacterCount()
2133
2134 awt::Rectangle aRectEndPos =
2135 getCharacterBounds(getCharacterCount());
2136
2137 if (rPoint.X - aRectEndPos.X >= 0 &&
2138 rPoint.X - aRectEndPos.X < aRectEndPos.Width &&
2139 rPoint.Y - aRectEndPos.Y >= 0 &&
2140 rPoint.Y - aRectEndPos.Y < aRectEndPos.Height)
2141 return getCharacterCount();
2142
2143 return -1;
2144 }
2145
2146 // ask core for position
2147 OSL_ENSURE( GetFrame() != nullptr, "The text frame has vanished!" )do { if (true && (!(GetFrame() != nullptr))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "2147" ": "), "%s", "The text frame has vanished!"); } }
while (false)
;
2148 OSL_ENSURE( GetFrame()->IsTextFrame(), "The text frame has mutated!" )do { if (true && (!(GetFrame()->IsTextFrame()))) {
sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "2148" ": "), "%s", "The text frame has mutated!"); } } while
(false)
;
2149 const SwTextFrame* pFrame = static_cast<const SwTextFrame*>( GetFrame() );
2150 // construct SwPosition (where GetModelPositionForViewPoint() will put the result into)
2151 SwTextNode* pNode = const_cast<SwTextNode*>(pFrame->GetTextNodeFirst());
2152 SwPosition aPos(*pNode, 0);
2153 SwCursorMoveState aMoveState;
2154 aMoveState.m_bPosMatchesBounds = true;
2155 const bool bSuccess = pFrame->GetModelPositionForViewPoint( &aPos, aCorePoint, &aMoveState );
2156
2157 TextFrameIndex nIndex = pFrame->MapModelToViewPos(aPos);
2158 if (TextFrameIndex(0) < nIndex)
2159 {
2160 assert(bSuccess)(static_cast <bool> (bSuccess) ? void (0) : __assert_fail
("bSuccess", "/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
, 2160, __extension__ __PRETTY_FUNCTION__))
;
2161 SwRect aResultRect;
2162 pFrame->GetCharRect( aResultRect, aPos );
2163 bool bVert = pFrame->IsVertical();
2164 bool bR2L = pFrame->IsRightToLeft();
2165
2166 if ( (!bVert && aResultRect.Pos().getX() > aCorePoint.getX()) ||
2167 ( bVert && aResultRect.Pos().getY() > aCorePoint.getY()) ||
2168 ( bR2L && aResultRect.Right() < aCorePoint.getX()) )
2169 {
2170 SwPosition aPosPrev(pFrame->MapViewToModelPos(nIndex - TextFrameIndex(1)));
2171 SwRect aResultRectPrev;
2172 pFrame->GetCharRect( aResultRectPrev, aPosPrev );
2173 if ( (!bVert && aResultRectPrev.Pos().getX() < aCorePoint.getX() && aResultRect.Pos().getY() == aResultRectPrev.Pos().getY()) ||
2174 ( bVert && aResultRectPrev.Pos().getY() < aCorePoint.getY() && aResultRect.Pos().getX() == aResultRectPrev.Pos().getX()) ||
2175 ( bR2L && aResultRectPrev.Right() > aCorePoint.getX() && aResultRect.Pos().getY() == aResultRectPrev.Pos().getY()) )
2176 {
2177 --nIndex;
2178 }
2179 }
2180 }
2181
2182 return bSuccess
2183 ? GetPortionData().GetAccessiblePosition(nIndex)
2184 : -1;
2185}
2186
2187OUString SwAccessibleParagraph::getSelectedText()
2188{
2189 SolarMutexGuard aGuard;
2190
2191 ThrowIfDisposed();
2192
2193 sal_Int32 nStart, nEnd;
2194 bool bSelected = GetSelection( nStart, nEnd );
2195 return bSelected
2196 ? GetString().copy( nStart, nEnd - nStart )
2197 : OUString();
2198}
2199
2200sal_Int32 SwAccessibleParagraph::getSelectionStart()
2201{
2202 SolarMutexGuard aGuard;
2203
2204 ThrowIfDisposed();
2205
2206 sal_Int32 nStart, nEnd;
2207 GetSelection( nStart, nEnd );
2208 return nStart;
2209}
2210
2211sal_Int32 SwAccessibleParagraph::getSelectionEnd()
2212{
2213 SolarMutexGuard aGuard;
2214
2215 ThrowIfDisposed();
2216
2217 sal_Int32 nStart, nEnd;
2218 GetSelection( nStart, nEnd );
2219 return nEnd;
2220}
2221
2222sal_Bool SwAccessibleParagraph::setSelection( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
2223{
2224 SolarMutexGuard aGuard;
2225
2226 ThrowIfDisposed();
2227
2228 // parameter checking
2229 sal_Int32 nLength = GetString().getLength();
2230 if ( ! IsValidRange( nStartIndex, nEndIndex, nLength ) )
2231 {
2232 throw lang::IndexOutOfBoundsException();
2233 }
2234
2235 bool bRet = false;
2236
2237 // get cursor shell
2238 SwCursorShell* pCursorShell = GetCursorShell();
2239 if( pCursorShell != nullptr )
2240 {
2241 // create pam for selection
2242 SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(GetFrame()));
2243 TextFrameIndex const nStart(GetPortionData().GetCoreViewPosition(nStartIndex));
2244 TextFrameIndex const nEnd(GetPortionData().GetCoreViewPosition(nEndIndex));
2245 SwPaM aPaM(pFrame->MapViewToModelPos(nStart));
2246 aPaM.SetMark();
2247 *aPaM.GetPoint() = pFrame->MapViewToModelPos(nEnd);
2248
2249 // set PaM at cursor shell
2250 bRet = Select( aPaM );
2251 }
2252
2253 return bRet;
2254}
2255
2256OUString SwAccessibleParagraph::getText()
2257{
2258 SolarMutexGuard aGuard;
2259
2260 ThrowIfDisposed();
2261
2262 return GetString();
2263}
2264
2265OUString SwAccessibleParagraph::getTextRange(
2266 sal_Int32 nStartIndex, sal_Int32 nEndIndex )
2267{
2268 SolarMutexGuard aGuard;
2269
2270 ThrowIfDisposed();
2271
2272 OUString sText( GetString() );
2273
2274 if ( !IsValidRange( nStartIndex, nEndIndex, sText.getLength() ) )
2275 throw lang::IndexOutOfBoundsException();
2276
2277 OrderRange( nStartIndex, nEndIndex );
2278 return sText.copy(nStartIndex, nEndIndex-nStartIndex );
2279}
2280
2281/*accessibility::*/TextSegment SwAccessibleParagraph::getTextAtIndex( sal_Int32 nIndex, sal_Int16 nTextType )
2282{
2283 SolarMutexGuard aGuard;
2284
2285 ThrowIfDisposed();
2286
2287 /*accessibility::*/TextSegment aResult;
2288 aResult.SegmentStart = -1;
2289 aResult.SegmentEnd = -1;
2290
2291 const OUString rText = GetString();
2292 // implement the silly specification that first position after
2293 // text must return an empty string, rather than throwing an
2294 // IndexOutOfBoundsException, except for LINE, where the last
2295 // line is returned
2296 if( nIndex == rText.getLength() && AccessibleTextType::LINE != nTextType )
2297 return aResult;
2298
2299 // with error checking
2300 i18n::Boundary aBound;
2301 bool bWord = GetTextBoundary( aBound, rText, nIndex, nTextType );
2302
2303 OSL_ENSURE( aBound.startPos >= 0, "illegal boundary" )do { if (true && (!(aBound.startPos >= 0))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "2303" ": "), "%s", "illegal boundary"); } } while (false
)
;
2304 OSL_ENSURE( aBound.startPos <= aBound.endPos, "illegal boundary" )do { if (true && (!(aBound.startPos <= aBound.endPos
))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "2304" ": "), "%s", "illegal boundary"); } } while (false
)
;
2305
2306 // return word (if present)
2307 if ( bWord )
2308 {
2309 aResult.SegmentText = rText.copy( aBound.startPos, aBound.endPos - aBound.startPos );
2310 aResult.SegmentStart = aBound.startPos;
2311 aResult.SegmentEnd = aBound.endPos;
2312 }
2313
2314 return aResult;
2315}
2316
2317/*accessibility::*/TextSegment SwAccessibleParagraph::getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 nTextType )
2318{
2319 SolarMutexGuard aGuard;
2320
2321 ThrowIfDisposed();
2322
2323 const OUString rText = GetString();
2324
2325 /*accessibility::*/TextSegment aResult;
2326 aResult.SegmentStart = -1;
2327 aResult.SegmentEnd = -1;
2328 //If nIndex = 0, then nobefore text so return -1 directly.
2329 if( nIndex == 0 )
2330 return aResult;
2331 //Tab will be return when call WORDTYPE
2332
2333 // get starting pos
2334 i18n::Boundary aBound;
2335 if (nIndex == rText.getLength())
2336 aBound.startPos = aBound.endPos = nIndex;
2337 else
2338 {
2339 bool bTmp = GetTextBoundary( aBound, rText, nIndex, nTextType );
2340
2341 if ( ! bTmp )
2342 aBound.startPos = aBound.endPos = nIndex;
2343 }
2344
2345 // now skip to previous word
2346 if (nTextType==2 || nTextType == 3)
2347 {
2348 i18n::Boundary preBound = aBound;
2349 while(preBound.startPos==aBound.startPos && nIndex > 0)
2350 {
2351 nIndex = min( nIndex, preBound.startPos ) - 1;
2352 if( nIndex < 0 ) break;
2353 GetTextBoundary( preBound, rText, nIndex, nTextType );
2354 }
2355 //if (nIndex>0)
2356 if (nIndex>=0)
2357 //Tab will be return when call WORDTYPE
2358 {
2359 aResult.SegmentText = rText.copy( preBound.startPos, preBound.endPos - preBound.startPos );
2360 aResult.SegmentStart = preBound.startPos;
2361 aResult.SegmentEnd = preBound.endPos;
2362 }
2363 }
2364 else
2365 {
2366 bool bWord = false;
2367 while( !bWord )
2368 {
2369 nIndex = min( nIndex, aBound.startPos ) - 1;
2370 if( nIndex >= 0 )
2371 {
2372 bWord = GetTextBoundary( aBound, rText, nIndex, nTextType );
2373 }
2374 else
2375 break; // exit if beginning of string is reached
2376 }
2377
2378 if (bWord && nIndex<rText.getLength())
2379 {
2380 aResult.SegmentText = rText.copy( aBound.startPos, aBound.endPos - aBound.startPos );
2381 aResult.SegmentStart = aBound.startPos;
2382 aResult.SegmentEnd = aBound.endPos;
2383 }
2384 }
2385 return aResult;
2386}
2387
2388/*accessibility::*/TextSegment SwAccessibleParagraph::getTextBehindIndex( sal_Int32 nIndex, sal_Int16 nTextType )
2389{
2390 SolarMutexGuard aGuard;
2391
2392 ThrowIfDisposed();
2393
2394 /*accessibility::*/TextSegment aResult;
2395 aResult.SegmentStart = -1;
2396 aResult.SegmentEnd = -1;
2397 const OUString rText = GetString();
2398
2399 // implement the silly specification that first position after
2400 // text must return an empty string, rather than throwing an
2401 // IndexOutOfBoundsException
2402 if( nIndex == rText.getLength() )
2403 return aResult;
2404
2405 // get first word, then skip to next word
2406 i18n::Boundary aBound;
2407 GetTextBoundary( aBound, rText, nIndex, nTextType );
2408 bool bWord = false;
2409 while( !bWord )
2410 {
2411 nIndex = max( sal_Int32(nIndex+1), aBound.endPos );
2412 if( nIndex < rText.getLength() )
2413 bWord = GetTextBoundary( aBound, rText, nIndex, nTextType );
2414 else
2415 break; // exit if end of string is reached
2416 }
2417
2418 if ( bWord )
2419 {
2420 aResult.SegmentText = rText.copy( aBound.startPos, aBound.endPos - aBound.startPos );
2421 aResult.SegmentStart = aBound.startPos;
2422 aResult.SegmentEnd = aBound.endPos;
2423 }
2424
2425/*
2426 sal_Bool bWord = sal_False;
2427 bWord = GetTextBoundary( aBound, rText, nIndex, nTextType );
2428
2429 if (nTextType==2)
2430 {
2431 Boundary nexBound=aBound;
2432
2433 // real current word
2434 if( nIndex <= aBound.endPos && nIndex >= aBound.startPos )
2435 {
2436 while(nexBound.endPos==aBound.endPos&&nIndex<rText.getLength())
2437 {
2438 // nIndex = max( (sal_Int32)(nIndex), nexBound.endPos) + 1;
2439 nIndex = max( (sal_Int32)(nIndex), nexBound.endPos) ;
2440 const sal_Unicode* pStr = rText.getStr();
2441 if (pStr)
2442 {
2443 if( pStr[nIndex] == sal_Unicode(' ') )
2444 nIndex++;
2445 }
2446 if( nIndex < rText.getLength() )
2447 {
2448 bWord = GetTextBoundary( nexBound, rText, nIndex, nTextType );
2449 }
2450 }
2451 }
2452
2453 if (bWord && nIndex<rText.getLength())
2454 {
2455 aResult.SegmentText = rText.copy( nexBound.startPos, nexBound.endPos - nexBound.startPos );
2456 aResult.SegmentStart = nexBound.startPos;
2457 aResult.SegmentEnd = nexBound.endPos;
2458 }
2459
2460 }
2461 else
2462 {
2463 bWord = sal_False;
2464 while( !bWord )
2465 {
2466 nIndex = max( (sal_Int32)(nIndex+1), aBound.endPos );
2467 if( nIndex < rText.getLength() )
2468 {
2469 bWord = GetTextBoundary( aBound, rText, nIndex, nTextType );
2470 }
2471 else
2472 break; // exit if end of string is reached
2473 }
2474 if (bWord && nIndex<rText.getLength())
2475 {
2476 aResult.SegmentText = rText.copy( aBound.startPos, aBound.endPos - aBound.startPos );
2477 aResult.SegmentStart = aBound.startPos;
2478 aResult.SegmentEnd = aBound.endPos;
2479 }
2480 }
2481*/
2482 return aResult;
2483}
2484
2485sal_Bool SwAccessibleParagraph::copyText( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
2486{
2487 SolarMutexGuard aGuard;
2488
2489 ThrowIfDisposed();
2490
2491 // select and copy (through dispatch mechanism)
2492 setSelection( nStartIndex, nEndIndex );
2493 ExecuteAtViewShell( SID_COPY(5000 + 711) );
2494 return true;
2495}
2496
2497sal_Bool SwAccessibleParagraph::scrollSubstringTo( sal_Int32 nStartIndex,
2498 sal_Int32 nEndIndex, AccessibleScrollType aScrollType )
2499{
2500 SolarMutexGuard aGuard;
2501
2502 ThrowIfDisposed();
2503
2504 // parameter checking
2505 sal_Int32 nLength = GetString().getLength();
2506 if ( ! IsValidRange( nStartIndex, nEndIndex, nLength ) )
2507 throw lang::IndexOutOfBoundsException();
2508
2509 vcl::Window *pWin = GetWindow();
2510 if ( ! pWin )
2511 throw uno::RuntimeException("no Window", static_cast<cppu::OWeakObject*>(this));
2512
2513 /* Start and end character bounds, in pixels, relative to the paragraph */
2514 awt::Rectangle startR, endR;
2515 startR = getCharacterBounds(nStartIndex);
2516 endR = getCharacterBounds(nEndIndex);
2517
2518 /* Adjust points to fit the bounding box of both bounds. */
2519 Point sP(std::min(startR.X, endR.X), startR.Y);
2520 Point eP(std::max(startR.X + startR.Width, endR.X + endR.Width), endR.Y + endR.Height);
2521
2522 /* Offset the values relative to the view shell frame */
2523 SwRect aFrameLogBounds( GetBounds( *(GetMap()) ) ); // twip rel to doc root
2524 Point aFramePixPos( GetMap()->CoreToPixel( aFrameLogBounds.SVRect() ).TopLeft() );
2525 sP += aFramePixPos;
2526 eP += aFramePixPos;
2527
2528 Point startPoint(GetMap()->PixelToCore(sP));
2529 Point endPoint(GetMap()->PixelToCore(eP));
2530
2531 switch (aScrollType)
2532 {
2533#ifdef notyet
2534 case AccessibleScrollType_SCROLL_TOP_LEFT:
2535 break;
2536 case AccessibleScrollType_SCROLL_BOTTOM_RIGHT:
2537 break;
2538 case AccessibleScrollType_SCROLL_TOP_EDGE:
2539 break;
2540 case AccessibleScrollType_SCROLL_BOTTOM_EDGE:
2541 break;
2542 case AccessibleScrollType_SCROLL_LEFT_EDGE:
2543 break;
2544 case AccessibleScrollType_SCROLL_RIGHT_EDGE:
2545 break;
2546#endif
2547 case AccessibleScrollType_SCROLL_ANYWHERE:
2548 break;
2549 default:
2550 return false;
2551 }
2552
2553 const SwRect aRect(startPoint, endPoint);
2554 SwViewShell* pViewShell = GetMap()->GetShell();
2555 OSL_ENSURE( pViewShell != nullptr, "View shell expected!" )do { if (true && (!(pViewShell != nullptr))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "2555" ": "), "%s", "View shell expected!"); } } while (
false)
;
2556
2557 ScrollMDI(pViewShell, aRect, USHRT_MAX(32767 *2 +1), USHRT_MAX(32767 *2 +1));
2558
2559 return true;
2560}
2561
2562// XAccessibleEditableText
2563
2564sal_Bool SwAccessibleParagraph::cutText( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
2565{
2566 SolarMutexGuard aGuard;
2567
2568 ThrowIfDisposed();
2569
2570 if( !IsEditableState() )
2571 return false;
2572
2573 // select and cut (through dispatch mechanism)
2574 setSelection( nStartIndex, nEndIndex );
2575 ExecuteAtViewShell( SID_CUT(5000 + 710) );
2576 return true;
2577}
2578
2579sal_Bool SwAccessibleParagraph::pasteText( sal_Int32 nIndex )
2580{
2581 SolarMutexGuard aGuard;
2582
2583 ThrowIfDisposed();
2584
2585 if( !IsEditableState() )
2586 return false;
2587
2588 // select and paste (through dispatch mechanism)
2589 setSelection( nIndex, nIndex );
2590 ExecuteAtViewShell( SID_PASTE(5000 + 712) );
2591 return true;
2592}
2593
2594sal_Bool SwAccessibleParagraph::deleteText( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
2595{
2596 return replaceText( nStartIndex, nEndIndex, OUString() );
2597}
2598
2599sal_Bool SwAccessibleParagraph::insertText( const OUString& sText, sal_Int32 nIndex )
2600{
2601 return replaceText( nIndex, nIndex, sText );
2602}
2603
2604sal_Bool SwAccessibleParagraph::replaceText(
2605 sal_Int32 nStartIndex, sal_Int32 nEndIndex,
2606 const OUString& sReplacement )
2607{
2608 SolarMutexGuard aGuard;
2609
2610 ThrowIfDisposed();
2611
2612 const OUString& rText = GetString();
2613
2614 if( !IsValidRange( nStartIndex, nEndIndex, rText.getLength() ) )
2615 throw lang::IndexOutOfBoundsException();
2616
2617 if( !IsEditableState() )
2618 return false;
2619
2620 // translate positions
2621 TextFrameIndex nStart;
2622 TextFrameIndex nEnd;
2623 bool bSuccess = GetPortionData().GetEditableRange(
2624 nStartIndex, nEndIndex, nStart, nEnd );
2625
2626 // edit only if the range is editable
2627 if( bSuccess )
2628 {
2629 SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(GetFrame()));
2630 // create SwPosition for nStartIndex
2631 SwPosition aStartPos(pFrame->MapViewToModelPos(nStart));
2632
2633 // create SwPosition for nEndIndex
2634 SwPosition aEndPos(pFrame->MapViewToModelPos(nEnd));
2635
2636 // now create XTextRange as helper and set string
2637 const uno::Reference<text::XTextRange> xRange(
2638 SwXTextRange::CreateXTextRange(
2639 const_cast<SwDoc&>(pFrame->GetDoc()), aStartPos, &aEndPos));
2640 xRange->setString(sReplacement);
2641
2642 // delete portion data
2643 ClearPortionData();
2644 }
2645
2646 return bSuccess;
2647
2648}
2649
2650sal_Bool SwAccessibleParagraph::setAttributes(
2651 sal_Int32 nStartIndex,
2652 sal_Int32 nEndIndex,
2653 const uno::Sequence<PropertyValue>& rAttributeSet )
2654{
2655 SolarMutexGuard aGuard;
2656
2657 ThrowIfDisposed();
2658
2659 const OUString& rText = GetString();
2660
2661 if( ! IsValidRange( nStartIndex, nEndIndex, rText.getLength() ) )
2662 throw lang::IndexOutOfBoundsException();
2663
2664 if( !IsEditableState() )
2665 return false;
2666
2667 // create a (dummy) text portion for the sole purpose of calling
2668 // setPropertyValue on it
2669 uno::Reference<XMultiPropertySet> xPortion = CreateUnoPortion( nStartIndex,
2670 nEndIndex );
2671
2672 // build sorted index array
2673 sal_Int32 nLength = rAttributeSet.getLength();
2674 const PropertyValue* pPairs = rAttributeSet.getConstArray();
2675 std::vector<sal_Int32> aIndices(nLength);
2676 std::iota(aIndices.begin(), aIndices.end(), 0);
2677 std::sort(aIndices.begin(), aIndices.end(), IndexCompare(pPairs));
2678
2679 // create sorted sequences according to index array
2680 uno::Sequence< OUString > aNames( nLength );
2681 OUString* pNames = aNames.getArray();
2682 uno::Sequence< uno::Any > aValues( nLength );
2683 uno::Any* pValues = aValues.getArray();
2684 for (sal_Int32 i = 0; i < nLength; ++i)
2685 {
2686 const PropertyValue& rVal = pPairs[aIndices[i]];
2687 pNames[i] = rVal.Name;
2688 pValues[i] = rVal.Value;
2689 }
2690 aIndices.clear();
2691
2692 // now set the values
2693 bool bRet = true;
2694 try
2695 {
2696 xPortion->setPropertyValues( aNames, aValues );
2697 }
2698 catch (const UnknownPropertyException&)
2699 {
2700 // error handling through return code!
2701 bRet = false;
2702 }
2703
2704 return bRet;
2705}
2706
2707sal_Bool SwAccessibleParagraph::setText( const OUString& sText )
2708{
2709 return replaceText(0, GetString().getLength(), sText);
2710}
2711
2712// XAccessibleSelection
2713
2714void SwAccessibleParagraph::selectAccessibleChild(
2715 sal_Int32 nChildIndex )
2716{
2717 ThrowIfDisposed();
2718
2719 m_aSelectionHelper.selectAccessibleChild(nChildIndex);
2720}
2721
2722sal_Bool SwAccessibleParagraph::isAccessibleChildSelected(
2723 sal_Int32 nChildIndex )
2724{
2725 ThrowIfDisposed();
2726
2727 return m_aSelectionHelper.isAccessibleChildSelected(nChildIndex);
2728}
2729
2730void SwAccessibleParagraph::clearAccessibleSelection( )
2731{
2732 ThrowIfDisposed();
2733}
2734
2735void SwAccessibleParagraph::selectAllAccessibleChildren( )
2736{
2737 ThrowIfDisposed();
2738
2739 m_aSelectionHelper.selectAllAccessibleChildren();
2740}
2741
2742sal_Int32 SwAccessibleParagraph::getSelectedAccessibleChildCount( )
2743{
2744 ThrowIfDisposed();
2745
2746 return m_aSelectionHelper.getSelectedAccessibleChildCount();
2747}
2748
2749uno::Reference<XAccessible> SwAccessibleParagraph::getSelectedAccessibleChild(
2750 sal_Int32 nSelectedChildIndex )
2751{
2752 ThrowIfDisposed();
2753
2754 return m_aSelectionHelper.getSelectedAccessibleChild(nSelectedChildIndex);
2755}
2756
2757// index has to be treated as global child index.
2758void SwAccessibleParagraph::deselectAccessibleChild(
2759 sal_Int32 nChildIndex )
2760{
2761 ThrowIfDisposed();
2762
2763 m_aSelectionHelper.deselectAccessibleChild( nChildIndex );
2764}
2765
2766// XAccessibleHypertext
2767
2768namespace {
2769
2770class SwHyperlinkIter_Impl
2771{
2772 SwTextFrame const& m_rFrame;
2773 sw::MergedAttrIter m_Iter;
2774 TextFrameIndex m_nStt;
2775 TextFrameIndex m_nEnd;
2776
2777public:
2778 explicit SwHyperlinkIter_Impl(const SwTextFrame & rTextFrame);
2779 const SwTextAttr *next(SwTextNode const** ppNode = nullptr);
2780
2781 TextFrameIndex startIdx() const { return m_nStt; }
2782 TextFrameIndex endIdx() const { return m_nEnd; }
2783};
2784
2785}
2786
2787SwHyperlinkIter_Impl::SwHyperlinkIter_Impl(const SwTextFrame & rTextFrame)
2788 : m_rFrame(rTextFrame)
2789 , m_Iter(rTextFrame)
2790 , m_nStt(rTextFrame.GetOffset())
2791{
2792 const SwTextFrame *const pFollFrame = rTextFrame.GetFollow();
2793 m_nEnd = pFollFrame ? pFollFrame->GetOffset() : TextFrameIndex(rTextFrame.GetText().getLength());
2794}
2795
2796const SwTextAttr *SwHyperlinkIter_Impl::next(SwTextNode const** ppNode)
2797{
2798 const SwTextAttr *pAttr = nullptr;
2799 if (ppNode)
2800 {
2801 *ppNode = nullptr;
2802 }
2803
2804 SwTextNode const* pNode(nullptr);
2805 while (SwTextAttr const*const pHt = m_Iter.NextAttr(&pNode))
2806 {
2807 if (RES_TXTATR_INETFMT == pHt->Which())
2808 {
2809 const TextFrameIndex nHtStt(m_rFrame.MapModelToView(pNode, pHt->GetStart()));
2810 const TextFrameIndex nHtEnd(m_rFrame.MapModelToView(pNode, pHt->GetAnyEnd()));
2811 if (nHtEnd > nHtStt &&
2812 ((nHtStt >= m_nStt && nHtStt < m_nEnd) ||
2813 (nHtEnd > m_nStt && nHtEnd <= m_nEnd)))
2814 {
2815 pAttr = pHt;
2816 if (ppNode)
2817 {
2818 *ppNode = pNode;
2819 }
2820 break;
2821 }
2822 }
2823 }
2824
2825 return pAttr;
2826};
2827
2828sal_Int32 SAL_CALL SwAccessibleParagraph::getHyperLinkCount()
2829{
2830 SolarMutexGuard aGuard;
2831
2832 ThrowIfDisposed();
2833
2834 sal_Int32 nCount = 0;
2835 // #i77108# - provide hyperlinks also in editable documents.
2836
2837 const SwTextFrame *pTextFrame = static_cast<const SwTextFrame*>( GetFrame() );
2838 SwHyperlinkIter_Impl aIter(*pTextFrame);
2839 while( aIter.next() )
2840 nCount++;
2841
2842 return nCount;
2843}
2844
2845uno::Reference< XAccessibleHyperlink > SAL_CALL
2846 SwAccessibleParagraph::getHyperLink( sal_Int32 nLinkIndex )
2847{
2848 SolarMutexGuard aGuard;
2849
2850 ThrowIfDisposed();
2851
2852 uno::Reference< XAccessibleHyperlink > xRet;
2853
2854 const SwTextFrame *pTextFrame = static_cast<const SwTextFrame*>( GetFrame() );
2855 SwHyperlinkIter_Impl aHIter(*pTextFrame);
2856 SwTextNode const* pNode(nullptr);
2857 SwTextAttr* pHt = const_cast<SwTextAttr*>(aHIter.next(&pNode));
2858 for (sal_Int32 nTIndex = 0; pHt && nTIndex <= nLinkIndex; ++nTIndex)
2859 {
2860 if( nTIndex == nLinkIndex )
2861 { // found
2862 if (!m_pHyperTextData)
2863 m_pHyperTextData.reset( new SwAccessibleHyperTextData );
2864 SwAccessibleHyperTextData::iterator aIter =
2865 m_pHyperTextData ->find( pHt );
2866 if (aIter != m_pHyperTextData->end())
2867 {
2868 xRet = (*aIter).second;
2869 }
2870 if (!xRet.is())
2871 {
2872 TextFrameIndex const nHintStart(pTextFrame->MapModelToView(pNode, pHt->GetStart()));
2873 TextFrameIndex const nHintEnd(pTextFrame->MapModelToView(pNode, pHt->GetAnyEnd()));
2874 const sal_Int32 nTmpHStt = GetPortionData().GetAccessiblePosition(
2875 max(aHIter.startIdx(), nHintStart));
2876 const sal_Int32 nTmpHEnd = GetPortionData().GetAccessiblePosition(
2877 min(aHIter.endIdx(), nHintEnd));
2878 xRet = new SwAccessibleHyperlink(*pHt,
2879 *this, nTmpHStt, nTmpHEnd );
2880 if (aIter != m_pHyperTextData->end())
2881 {
2882 (*aIter).second = xRet;
2883 }
2884 else
2885 {
2886 m_pHyperTextData->emplace( pHt, xRet );
2887 }
2888 }
2889 break;
2890 }
2891
2892 // iterate next hyperlink
2893 pHt = const_cast<SwTextAttr*>(aHIter.next(&pNode));
2894 }
2895 if( !xRet.is() )
2896 throw lang::IndexOutOfBoundsException();
2897
2898 return xRet;
2899}
2900
2901sal_Int32 SAL_CALL SwAccessibleParagraph::getHyperLinkIndex( sal_Int32 nCharIndex )
2902{
2903 SolarMutexGuard aGuard;
2904
2905 ThrowIfDisposed();
2906
2907 // parameter checking
2908 sal_Int32 nLength = GetString().getLength();
2909 if ( ! IsValidPosition( nCharIndex, nLength ) )
2910 {
2911 throw lang::IndexOutOfBoundsException();
2912 }
2913
2914 sal_Int32 nRet = -1;
2915 // #i77108#
2916 {
2917 const SwTextFrame *pTextFrame = static_cast<const SwTextFrame*>( GetFrame() );
2918 SwHyperlinkIter_Impl aHIter(*pTextFrame);
2919
2920 const TextFrameIndex nIdx = GetPortionData().GetCoreViewPosition(nCharIndex);
2921 sal_Int32 nPos = 0;
2922 SwTextNode const* pNode(nullptr);
2923 const SwTextAttr *pHt = aHIter.next(&pNode);
2924 while (pHt && (nIdx < pTextFrame->MapModelToView(pNode, pHt->GetStart())
2925 || nIdx >= pTextFrame->MapModelToView(pNode, pHt->GetAnyEnd())))
2926 {
2927 pHt = aHIter.next(&pNode);
2928 nPos++;
2929 }
2930
2931 if( pHt )
2932 nRet = nPos;
2933 }
2934
2935 if (nRet == -1)
2936 throw lang::IndexOutOfBoundsException();
2937 return nRet;
2938}
2939
2940// #i71360#, #i108125# - adjustments for change tracking text markup
2941sal_Int32 SAL_CALL SwAccessibleParagraph::getTextMarkupCount( sal_Int32 nTextMarkupType )
2942{
2943 SolarMutexGuard g;
2944
2945 std::unique_ptr<SwTextMarkupHelper> pTextMarkupHelper;
2946 switch ( nTextMarkupType )
2947 {
2948 case text::TextMarkupType::TRACK_CHANGE_INSERTION:
2949 case text::TextMarkupType::TRACK_CHANGE_DELETION:
2950 case text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE:
2951 {
2952 pTextMarkupHelper.reset( new SwTextMarkupHelper(
2953 GetPortionData(),
2954 *(mpParaChangeTrackInfo->getChangeTrackingTextMarkupList( nTextMarkupType ) )) );
2955 }
2956 break;
2957 default:
2958 {
2959 SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(GetFrame()));
2960 pTextMarkupHelper.reset(new SwTextMarkupHelper(GetPortionData(), *pFrame));
2961 }
2962 }
2963
2964 return pTextMarkupHelper->getTextMarkupCount( nTextMarkupType );
2965}
2966
2967//MSAA Extension Implementation in app module
2968sal_Bool SAL_CALL SwAccessibleParagraph::scrollToPosition( const css::awt::Point&, sal_Bool )
2969{
2970 return false;
2971}
2972
2973sal_Int32 SAL_CALL SwAccessibleParagraph::getSelectedPortionCount( )
2974{
2975 SolarMutexGuard g;
2976
2977 sal_Int32 nSelected = 0;
2978 SwPaM* pCursor = GetCursor( true );
2979 if( pCursor != nullptr )
2980 {
2981 // get SwPosition for my node
2982 SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(GetFrame()));
2983 sal_uLong nFirstNode(pFrame->GetTextNodeFirst()->GetIndex());
2984 sal_uLong nLastNode;
2985 if (sw::MergedPara const*const pMerged = pFrame->GetMergedPara())
2986 {
2987 nLastNode = pMerged->pLastNode->GetIndex();
2988 }
2989 else
2990 {
2991 nLastNode = nFirstNode;
2992 }
2993
2994 // iterate over ring
2995 for(SwPaM& rTmpCursor : pCursor->GetRingContainer())
2996 {
2997 // ignore, if no mark
2998 if( rTmpCursor.HasMark() )
2999 {
3000 // check whether frame's node(s) are 'inside' pCursor
3001 SwPosition* pStart = rTmpCursor.Start();
3002 sal_uLong nStartIndex = pStart->nNode.GetIndex();
3003 SwPosition* pEnd = rTmpCursor.End();
3004 sal_uLong nEndIndex = pEnd->nNode.GetIndex();
3005 if ((nStartIndex <= nLastNode) && (nFirstNode <= nEndIndex))
3006 {
3007 nSelected++;
3008 }
3009 // else: this PaM doesn't point to this paragraph
3010 }
3011 // else: this PaM is collapsed and doesn't select anything
3012 }
3013 }
3014 return nSelected;
3015
3016}
3017
3018sal_Int32 SAL_CALL SwAccessibleParagraph::getSeletedPositionStart( sal_Int32 nSelectedPortionIndex )
3019{
3020 SolarMutexGuard aGuard;
3021
3022 ThrowIfDisposed();
3023
3024 sal_Int32 nStart, nEnd;
3025 /*sal_Bool bSelected = */GetSelectionAtIndex(&nSelectedPortionIndex, nStart, nEnd );
3026 return nStart;
3027}
3028
3029sal_Int32 SAL_CALL SwAccessibleParagraph::getSeletedPositionEnd( sal_Int32 nSelectedPortionIndex )
3030{
3031 SolarMutexGuard aGuard;
3032
3033 ThrowIfDisposed();
3034
3035 sal_Int32 nStart, nEnd;
1
'nEnd' declared without an initial value
3036 /*sal_Bool bSelected = */GetSelectionAtIndex(&nSelectedPortionIndex, nStart, nEnd );
2
Calling 'SwAccessibleParagraph::GetSelectionAtIndex'
6
Returning from 'SwAccessibleParagraph::GetSelectionAtIndex'
3037 return nEnd;
7
Undefined or garbage value returned to caller
3038}
3039
3040sal_Bool SAL_CALL SwAccessibleParagraph::removeSelection( sal_Int32 selectionIndex )
3041{
3042 SolarMutexGuard g;
3043
3044 if(selectionIndex < 0) return false;
3045
3046 sal_Int32 nSelected = selectionIndex;
3047
3048 // get the selection, and test whether it affects our text node
3049 SwPaM* pCursor = GetCursor( true );
3050
3051 if( pCursor != nullptr )
3052 {
3053 bool bRet = false;
3054
3055 // get SwPosition for my node
3056 SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(GetFrame()));
3057 sal_uLong nFirstNode(pFrame->GetTextNodeFirst()->GetIndex());
3058 sal_uLong nLastNode;
3059 if (sw::MergedPara const*const pMerged = pFrame->GetMergedPara())
3060 {
3061 nLastNode = pMerged->pLastNode->GetIndex();
3062 }
3063 else
3064 {
3065 nLastNode = nFirstNode;
3066 }
3067
3068 // iterate over ring
3069 SwPaM* pRingStart = pCursor;
3070 do
3071 {
3072 // ignore, if no mark
3073 if( pCursor->HasMark() )
3074 {
3075 // check whether frame's node(s) are 'inside' pCursor
3076 SwPosition* pStart = pCursor->Start();
3077 sal_uLong nStartIndex = pStart->nNode.GetIndex();
3078 SwPosition* pEnd = pCursor->End();
3079 sal_uLong nEndIndex = pEnd->nNode.GetIndex();
3080 if ((nStartIndex <= nLastNode) && (nFirstNode <= nEndIndex))
3081 {
3082 if( nSelected == 0 )
3083 {
3084 pCursor->MoveTo(nullptr);
3085 delete pCursor;
3086 bRet = true;
3087 }
3088 else
3089 {
3090 nSelected--;
3091 }
3092 }
3093 }
3094 // else: this PaM is collapsed and doesn't select anything
3095 if(!bRet)
3096 pCursor = pCursor->GetNext();
3097 }
3098 while( !bRet && (pCursor != pRingStart) );
3099 }
3100 return true;
3101}
3102
3103sal_Int32 SAL_CALL SwAccessibleParagraph::addSelection( sal_Int32, sal_Int32 startOffset, sal_Int32 endOffset)
3104{
3105 SolarMutexGuard aGuard;
3106
3107 ThrowIfDisposed();
3108
3109 // parameter checking
3110 sal_Int32 nLength = GetString().getLength();
3111 if ( ! IsValidRange( startOffset, endOffset, nLength ) )
3112 {
3113 throw lang::IndexOutOfBoundsException();
3114 }
3115
3116 sal_Int32 nSelectedCount = getSelectedPortionCount();
3117 for ( sal_Int32 i = nSelectedCount ; i >= 0 ; i--)
3118 {
3119 sal_Int32 nStart, nEnd;
3120 bool bSelected = GetSelectionAtIndex(&i, nStart, nEnd );
3121 if(bSelected)
3122 {
3123 if(nStart <= nEnd )
3124 {
3125 if (( startOffset>=nStart && startOffset <=nEnd ) || //startOffset in a selection
3126 ( endOffset>=nStart && endOffset <=nEnd ) || //endOffset in a selection
3127 ( startOffset <= nStart && endOffset >=nEnd) || //start and end include the old selection
3128 ( startOffset >= nStart && endOffset <=nEnd) )
3129 {
3130 removeSelection(i);
3131 }
3132
3133 }
3134 else
3135 {
3136 if (( startOffset>=nEnd && startOffset <=nStart ) || //startOffset in a selection
3137 ( endOffset>=nEnd && endOffset <=nStart ) || //endOffset in a selection
3138 ( startOffset <= nStart && endOffset >=nEnd) || //start and end include the old selection
3139 ( startOffset >= nStart && endOffset <=nEnd) )
3140
3141 {
3142 removeSelection(i);
3143 }
3144 }
3145 }
3146
3147 }
3148
3149 // get cursor shell
3150 SwCursorShell* pCursorShell = GetCursorShell();
3151 if( pCursorShell != nullptr )
3152 {
3153 // create pam for selection
3154 pCursorShell->StartAction();
3155 SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(GetFrame()));
3156 SwPaM* aPaM = pCursorShell->CreateCursor();
3157 aPaM->SetMark();
3158 *aPaM->GetPoint() = pFrame->MapViewToModelPos(GetPortionData().GetCoreViewPosition(startOffset));
3159 *aPaM->GetMark() = pFrame->MapViewToModelPos(GetPortionData().GetCoreViewPosition(endOffset));
3160 pCursorShell->EndAction();
3161 }
3162
3163 return 0;
3164}
3165
3166/*accessibility::*/TextSegment SAL_CALL
3167 SwAccessibleParagraph::getTextMarkup( sal_Int32 nTextMarkupIndex,
3168 sal_Int32 nTextMarkupType )
3169{
3170 SolarMutexGuard g;
3171
3172 std::unique_ptr<SwTextMarkupHelper> pTextMarkupHelper;
3173 switch ( nTextMarkupType )
3174 {
3175 case text::TextMarkupType::TRACK_CHANGE_INSERTION:
3176 case text::TextMarkupType::TRACK_CHANGE_DELETION:
3177 case text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE:
3178 {
3179 pTextMarkupHelper.reset( new SwTextMarkupHelper(
3180 GetPortionData(),
3181 *(mpParaChangeTrackInfo->getChangeTrackingTextMarkupList( nTextMarkupType ) )) );
3182 }
3183 break;
3184 default:
3185 {
3186 SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(GetFrame()));
3187 pTextMarkupHelper.reset(new SwTextMarkupHelper(GetPortionData(), *pFrame));
3188 }
3189 }
3190
3191 return pTextMarkupHelper->getTextMarkup( nTextMarkupIndex, nTextMarkupType );
3192}
3193
3194uno::Sequence< /*accessibility::*/TextSegment > SAL_CALL
3195 SwAccessibleParagraph::getTextMarkupAtIndex( sal_Int32 nCharIndex,
3196 sal_Int32 nTextMarkupType )
3197{
3198 SolarMutexGuard g;
3199
3200 // parameter checking
3201 const sal_Int32 nLength = GetString().getLength();
3202 if ( ! IsValidPosition( nCharIndex, nLength ) )
3203 {
3204 throw lang::IndexOutOfBoundsException();
3205 }
3206
3207 std::unique_ptr<SwTextMarkupHelper> pTextMarkupHelper;
3208 switch ( nTextMarkupType )
3209 {
3210 case text::TextMarkupType::TRACK_CHANGE_INSERTION:
3211 case text::TextMarkupType::TRACK_CHANGE_DELETION:
3212 case text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE:
3213 {
3214 pTextMarkupHelper.reset( new SwTextMarkupHelper(
3215 GetPortionData(),
3216 *(mpParaChangeTrackInfo->getChangeTrackingTextMarkupList( nTextMarkupType ) )) );
3217 }
3218 break;
3219 default:
3220 {
3221 SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(GetFrame()));
3222 pTextMarkupHelper.reset(new SwTextMarkupHelper(GetPortionData(), *pFrame));
3223 }
3224 }
3225
3226 return pTextMarkupHelper->getTextMarkupAtIndex( nCharIndex, nTextMarkupType );
3227}
3228
3229// #i89175#
3230sal_Int32 SAL_CALL SwAccessibleParagraph::getLineNumberAtIndex( sal_Int32 nIndex )
3231{
3232 SolarMutexGuard g;
3233
3234 // parameter checking
3235 const sal_Int32 nLength = GetString().getLength();
3236 if ( ! IsValidPosition( nIndex, nLength ) )
3237 {
3238 throw lang::IndexOutOfBoundsException();
3239 }
3240
3241 const sal_Int32 nLineNo = GetPortionData().GetLineNo( nIndex );
3242 return nLineNo;
3243}
3244
3245/*accessibility::*/TextSegment SAL_CALL
3246 SwAccessibleParagraph::getTextAtLineNumber( sal_Int32 nLineNo )
3247{
3248 SolarMutexGuard g;
3249
3250 // parameter checking
3251 if ( nLineNo < 0 ||
3252 nLineNo >= GetPortionData().GetLineCount() )
3253 {
3254 throw lang::IndexOutOfBoundsException();
3255 }
3256
3257 i18n::Boundary aLineBound;
3258 GetPortionData().GetBoundaryOfLine( nLineNo, aLineBound );
3259
3260 /*accessibility::*/TextSegment aTextAtLine;
3261 const OUString rText = GetString();
3262 aTextAtLine.SegmentText = rText.copy( aLineBound.startPos,
3263 aLineBound.endPos - aLineBound.startPos );
3264 aTextAtLine.SegmentStart = aLineBound.startPos;
3265 aTextAtLine.SegmentEnd = aLineBound.endPos;
3266
3267 return aTextAtLine;
3268}
3269
3270/*accessibility::*/TextSegment SAL_CALL SwAccessibleParagraph::getTextAtLineWithCaret()
3271{
3272 SolarMutexGuard g;
3273
3274 const sal_Int32 nLineNoOfCaret = getNumberOfLineWithCaret();
3275
3276 if ( nLineNoOfCaret >= 0 &&
3277 nLineNoOfCaret < GetPortionData().GetLineCount() )
3278 {
3279 return getTextAtLineNumber( nLineNoOfCaret );
3280 }
3281
3282 return /*accessibility::*/TextSegment();
3283}
3284
3285sal_Int32 SAL_CALL SwAccessibleParagraph::getNumberOfLineWithCaret()
3286{
3287 SolarMutexGuard g;
3288
3289 const sal_Int32 nCaretPos = getCaretPosition();
3290 const sal_Int32 nLength = GetString().getLength();
3291 if ( !IsValidPosition( nCaretPos, nLength ) )
3292 {
3293 return -1;
3294 }
3295
3296 sal_Int32 nLineNo = GetPortionData().GetLineNo( nCaretPos );
3297
3298 // special handling for cursor positioned at end of text line via End key
3299 if ( nCaretPos != 0 )
3300 {
3301 i18n::Boundary aLineBound;
3302 GetPortionData().GetBoundaryOfLine( nLineNo, aLineBound );
3303 if ( nCaretPos == aLineBound.startPos )
3304 {
3305 SwCursorShell* pCursorShell = SwAccessibleParagraph::GetCursorShell();
3306 if ( pCursorShell != nullptr )
3307 {
3308 const awt::Rectangle aCharRect = getCharacterBounds( nCaretPos );
3309
3310 const SwRect& aCursorCoreRect = pCursorShell->GetCharRect();
3311 // translate core coordinates into accessibility coordinates
3312 vcl::Window *pWin = GetWindow();
3313 if (!pWin)
3314 {
3315 throw uno::RuntimeException("no Window", static_cast<cppu::OWeakObject*>(this));
3316 }
3317
3318 tools::Rectangle aScreenRect( GetMap()->CoreToPixel( aCursorCoreRect.SVRect() ));
3319
3320 SwRect aFrameLogBounds( GetBounds( *(GetMap()) ) ); // twip rel to doc root
3321 Point aFramePixPos( GetMap()->CoreToPixel( aFrameLogBounds.SVRect() ).TopLeft() );
3322 aScreenRect.Move( -aFramePixPos.getX(), -aFramePixPos.getY() );
3323
3324 // convert into AWT Rectangle
3325 const awt::Rectangle aCursorRect( aScreenRect.Left(),
3326 aScreenRect.Top(),
3327 aScreenRect.GetWidth(),
3328 aScreenRect.GetHeight() );
3329
3330 if ( aCharRect.X != aCursorRect.X ||
3331 aCharRect.Y != aCursorRect.Y )
3332 {
3333 --nLineNo;
3334 }
3335 }
3336 }
3337 }
3338
3339 return nLineNo;
3340}
3341
3342// #i108125#
3343void SwAccessibleParagraph::Notify(SfxBroadcaster&, const SfxHint&)
3344{
3345 mpParaChangeTrackInfo->reset();
3346}
3347
3348bool SwAccessibleParagraph::GetSelectionAtIndex(
3349 sal_Int32 * pSelection, sal_Int32& nStart, sal_Int32& nEnd)
3350{
3351 if (pSelection
2.1
'pSelection' is non-null
&& *pSelection < 0) return false;
3
Assuming the condition is true
4
Taking true branch
5
Returning without writing to 'nEnd'
3352
3353 bool bRet = false;
3354 nStart = -1;
3355 nEnd = -1;
3356
3357 // get the selection, and test whether it affects our text node
3358 SwPaM* pCursor = GetCursor( true );
3359 if( pCursor != nullptr )
3360 {
3361 // get SwPosition for my node
3362 SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(GetFrame()));
3363 sal_uLong nFirstNode(pFrame->GetTextNodeFirst()->GetIndex());
3364 sal_uLong nLastNode;
3365 if (sw::MergedPara const*const pMerged = pFrame->GetMergedPara())
3366 {
3367 nLastNode = pMerged->pLastNode->GetIndex();
3368 }
3369 else
3370 {
3371 nLastNode = nFirstNode;
3372 }
3373
3374 // iterate over ring
3375 for(SwPaM& rTmpCursor : pCursor->GetRingContainer())
3376 {
3377 // ignore, if no mark
3378 if( rTmpCursor.HasMark() )
3379 {
3380 // check whether frame's node(s) are 'inside' pCursor
3381 SwPosition* pStart = rTmpCursor.Start();
3382 sal_uLong nStartIndex = pStart->nNode.GetIndex();
3383 SwPosition* pEnd = rTmpCursor.End();
3384 sal_uLong nEndIndex = pEnd->nNode.GetIndex();
3385 if ((nStartIndex <= nLastNode) && (nFirstNode <= nEndIndex))
3386 {
3387 if (!pSelection || *pSelection == 0)
3388 {
3389 // translate start and end positions
3390
3391 // start position
3392 sal_Int32 nLocalStart = -1;
3393 if (nStartIndex < nFirstNode)
3394 {
3395 // selection starts in previous node:
3396 // then our local selection starts with the paragraph
3397 nLocalStart = 0;
3398 }
3399 else
3400 {
3401 assert(FrameContainsNode(*pFrame, nStartIndex))(static_cast <bool> (FrameContainsNode(*pFrame, nStartIndex
)) ? void (0) : __assert_fail ("FrameContainsNode(*pFrame, nStartIndex)"
, "/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
, 3401, __extension__ __PRETTY_FUNCTION__))
;
3402
3403 // selection starts in this node:
3404 // then check whether it's before or inside our part of
3405 // the paragraph, and if so, get the proper position
3406 const TextFrameIndex nCoreStart =
3407 pFrame->MapModelToViewPos(*pStart);
3408 if( nCoreStart <
3409 GetPortionData().GetFirstValidCorePosition() )
3410 {
3411 nLocalStart = 0;
3412 }
3413 else if( nCoreStart <=
3414 GetPortionData().GetLastValidCorePosition() )
3415 {
3416 SAL_WARN_IF(do { if (true && (!GetPortionData().IsValidCorePosition
( nCoreStart))) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.a11y")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "problem determining valid core position"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y"
), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3420" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "problem determining valid core position"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "problem determining valid core position"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3420" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "problem determining valid core position") == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y")
, ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3420" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "problem determining valid core position"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "problem determining valid core position"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3420" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
3417 !GetPortionData().IsValidCorePosition(do { if (true && (!GetPortionData().IsValidCorePosition
( nCoreStart))) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.a11y")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "problem determining valid core position"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y"
), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3420" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "problem determining valid core position"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "problem determining valid core position"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3420" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "problem determining valid core position") == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y")
, ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3420" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "problem determining valid core position"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "problem determining valid core position"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3420" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
3418 nCoreStart),do { if (true && (!GetPortionData().IsValidCorePosition
( nCoreStart))) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.a11y")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "problem determining valid core position"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y"
), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3420" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "problem determining valid core position"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "problem determining valid core position"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3420" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "problem determining valid core position") == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y")
, ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3420" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "problem determining valid core position"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "problem determining valid core position"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3420" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
3419 "sw.a11y",do { if (true && (!GetPortionData().IsValidCorePosition
( nCoreStart))) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.a11y")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "problem determining valid core position"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y"
), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3420" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "problem determining valid core position"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "problem determining valid core position"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3420" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "problem determining valid core position") == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y")
, ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3420" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "problem determining valid core position"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "problem determining valid core position"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3420" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
3420 "problem determining valid core position")do { if (true && (!GetPortionData().IsValidCorePosition
( nCoreStart))) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.a11y")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "problem determining valid core position"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y"
), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3420" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "problem determining valid core position"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "problem determining valid core position"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3420" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "problem determining valid core position") == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y")
, ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3420" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "problem determining valid core position"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "problem determining valid core position"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3420" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
3421
3422 nLocalStart =
3423 GetPortionData().GetAccessiblePosition(
3424 nCoreStart );
3425 }
3426 }
3427
3428 // end position
3429 sal_Int32 nLocalEnd = -1;
3430 if (nLastNode < nEndIndex)
3431 {
3432 // selection ends in following node:
3433 // then our local selection extends to the end
3434 nLocalEnd = GetPortionData().GetAccessibleString().
3435 getLength();
3436 }
3437 else
3438 {
3439 assert(FrameContainsNode(*pFrame, nEndIndex))(static_cast <bool> (FrameContainsNode(*pFrame, nEndIndex
)) ? void (0) : __assert_fail ("FrameContainsNode(*pFrame, nEndIndex)"
, "/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
, 3439, __extension__ __PRETTY_FUNCTION__))
;
3440
3441 // selection ends in this node: then select everything
3442 // before our part of the node
3443 const TextFrameIndex nCoreEnd =
3444 pFrame->MapModelToViewPos(*pEnd);
3445 if( nCoreEnd >
3446 GetPortionData().GetLastValidCorePosition() )
3447 {
3448 // selection extends beyond out part of this para
3449 nLocalEnd = GetPortionData().GetAccessibleString().
3450 getLength();
3451 }
3452 else if( nCoreEnd >=
3453 GetPortionData().GetFirstValidCorePosition() )
3454 {
3455 // selection is inside our part of this para
3456 SAL_WARN_IF(do { if (true && (!GetPortionData().IsValidCorePosition
( nCoreEnd))) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.a11y")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "problem determining valid core position"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y"
), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3460" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "problem determining valid core position"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "problem determining valid core position"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3460" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "problem determining valid core position") == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y")
, ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3460" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "problem determining valid core position"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "problem determining valid core position"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3460" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
3457 !GetPortionData().IsValidCorePosition(do { if (true && (!GetPortionData().IsValidCorePosition
( nCoreEnd))) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.a11y")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "problem determining valid core position"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y"
), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3460" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "problem determining valid core position"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "problem determining valid core position"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3460" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "problem determining valid core position") == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y")
, ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3460" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "problem determining valid core position"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "problem determining valid core position"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3460" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
3458 nCoreEnd),do { if (true && (!GetPortionData().IsValidCorePosition
( nCoreEnd))) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.a11y")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "problem determining valid core position"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y"
), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3460" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "problem determining valid core position"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "problem determining valid core position"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3460" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "problem determining valid core position") == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y")
, ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3460" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "problem determining valid core position"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "problem determining valid core position"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3460" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
3459 "sw.a11y",do { if (true && (!GetPortionData().IsValidCorePosition
( nCoreEnd))) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.a11y")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "problem determining valid core position"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y"
), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3460" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "problem determining valid core position"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "problem determining valid core position"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3460" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "problem determining valid core position") == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y")
, ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3460" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "problem determining valid core position"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "problem determining valid core position"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3460" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
3460 "problem determining valid core position")do { if (true && (!GetPortionData().IsValidCorePosition
( nCoreEnd))) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.a11y")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "problem determining valid core position"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y"
), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3460" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "problem determining valid core position"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "problem determining valid core position"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3460" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "problem determining valid core position") == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y")
, ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3460" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "problem determining valid core position"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "problem determining valid core position"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.a11y"), ("/home/maarten/src/libreoffice/core/sw/source/core/access/accpara.cxx"
":" "3460" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
3461
3462 nLocalEnd = GetPortionData().GetAccessiblePosition(
3463 nCoreEnd );
3464 }
3465 }
3466
3467 if( ( nLocalStart != -1 ) && ( nLocalEnd != -1 ) )
3468 {
3469 nStart = nLocalStart;
3470 nEnd = nLocalEnd;
3471 bRet = true;
3472 }
3473 } // if hit the index
3474 else
3475 {
3476 --*pSelection;
3477 }
3478 }
3479 // else: this PaM doesn't point to this paragraph
3480 }
3481 // else: this PaM is collapsed and doesn't select anything
3482 if(bRet)
3483 break;
3484 }
3485 }
3486 // else: nocursor -> no selection
3487
3488 if (pSelection && bRet)
3489 {
3490 sal_Int32 nCaretPos = GetCaretPos();
3491 if( nStart == nCaretPos )
3492 {
3493 sal_Int32 tmp = nStart;
3494 nStart = nEnd;
3495 nEnd = tmp;
3496 }
3497 }
3498 return bRet;
3499}
3500
3501sal_Int16 SAL_CALL SwAccessibleParagraph::getAccessibleRole()
3502{
3503 SolarMutexGuard g;
3504
3505 //Get the real heading level, Heading1 ~ Heading10
3506 if (m_nHeadingLevel > 0)
3507 {
3508 return AccessibleRole::HEADING;
3509 }
3510 else
3511 {
3512 return AccessibleRole::PARAGRAPH;
3513 }
3514}
3515
3516//Get the real heading level, Heading1 ~ Heading10
3517sal_Int32 SwAccessibleParagraph::GetRealHeadingLevel()
3518{
3519 uno::Reference< css::beans::XPropertySet > xPortion = CreateUnoPortion( 0, 0 );
3520 uno::Any styleAny = xPortion->getPropertyValue( "ParaStyleName" );
3521 OUString sValue;
3522 if (styleAny >>= sValue)
3523 {
3524 sal_Int32 length = sValue.getLength();
3525 if (length == 9 || length == 10)
3526 {
3527 OUString headStr = sValue.copy(0, 7);
3528 if (headStr == "Heading")
3529 {
3530 OUString intStr = sValue.copy(8);
3531 sal_Int32 headingLevel = intStr.toInt32();
3532 return headingLevel;
3533 }
3534 }
3535 }
3536 return -1;
3537}
3538
3539uno::Any SAL_CALL SwAccessibleParagraph::getExtendedAttributes()
3540{
3541 SolarMutexGuard g;
3542
3543 uno::Any Ret;
3544 OUString strHeading("heading-level:");
3545 if( m_nHeadingLevel >= 0 )
3546 strHeading += OUString::number(m_nHeadingLevel);
3547 // tdf#84102: expose the same attribute with the name "level"
3548 strHeading += ";level:";
3549 if( m_nHeadingLevel >= 0 )
3550 strHeading += OUString::number(m_nHeadingLevel);
3551 strHeading += ";";
3552
3553 Ret <<= strHeading;
3554
3555 return Ret;
3556}
3557
3558/* vim:set shiftwidth=4 softtabstop=4 expandtab: */