1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_accessibility.hxx"
26
27 #ifndef _TOOLKIT_AWT_VCLXACCESSIBLECOMPONENT_HXX_
28 #include <accessibility/extended/textwindowaccessibility.hxx>
29 #endif
30 #include "comphelper/accessibleeventnotifier.hxx"
31 #include "unotools/accessiblerelationsethelper.hxx"
32 #include <unotools/accessiblestatesethelper.hxx>
33 #include <vcl/window.hxx>
34 #include <toolkit/helper/convert.hxx>
35
36 #include <algorithm>
37 #include <vector>
38 #include <hash_map>
39
40 namespace css = ::com::sun::star;
41
42 namespace accessibility
43 {
44 ::sal_Int32 getSelectionType(::sal_Int32 nNewFirstPara, ::sal_Int32 nNewFirstPos, ::sal_Int32 nNewLastPara, ::sal_Int32 nNewLastPos);
45 void sendEvent(::sal_Int32 start, ::sal_Int32 end, ::sal_Int16 nEventId);
46
47 // Both ::osl::Mutex and ParagraphBase implement acquire and release, and thus
48 // ::rtl::Reference< Paragraph > does not work. So ParagraphImpl was factored
49 // out and ::rtl::Reference< ParagraphImpl > is used instead.
50 class Paragraph: private ::osl::Mutex, public ParagraphImpl
51 {
52 public:
Paragraph(::rtl::Reference<Document> const & rDocument,Paragraphs::size_type nNumber)53 inline Paragraph(::rtl::Reference< Document > const & rDocument,
54 Paragraphs::size_type nNumber):
55 ParagraphImpl(rDocument, nNumber, *this) {}
56 };
57
startListening(::SfxBroadcaster & rNotifier)58 void SfxListenerGuard::startListening(::SfxBroadcaster & rNotifier)
59 {
60 OSL_ENSURE(m_pNotifier == 0, "called more than once");
61 m_pNotifier = &rNotifier;
62 m_rListener.StartListening(*m_pNotifier, true);
63 }
64
endListening()65 void SfxListenerGuard::endListening()
66 {
67 if (m_pNotifier != 0)
68 {
69 m_rListener.EndListening(*m_pNotifier);
70 m_pNotifier = 0;
71 }
72 }
73
startListening(::Window & rNotifier)74 void WindowListenerGuard::startListening(::Window & rNotifier)
75 {
76 OSL_ENSURE(m_pNotifier == 0, "called more than once");
77 m_pNotifier = &rNotifier;
78 m_pNotifier->AddEventListener(m_aListener);
79 }
80
endListening()81 void WindowListenerGuard::endListening()
82 {
83 if (m_pNotifier != 0)
84 {
85 m_pNotifier->RemoveEventListener(m_aListener);
86 m_pNotifier = 0;
87 }
88 }
89
ParagraphImpl(::rtl::Reference<Document> const & rDocument,Paragraphs::size_type nNumber,::osl::Mutex & rMutex)90 ParagraphImpl::ParagraphImpl(::rtl::Reference< Document > const & rDocument,
91 Paragraphs::size_type nNumber,
92 ::osl::Mutex & rMutex):
93 ParagraphBase(rMutex),
94 m_xDocument(rDocument),
95 m_nNumber(nNumber),
96 m_nClientId(0)
97 {
98 m_aParagraphText = m_xDocument->retrieveParagraphText(this);
99 }
100
101 void
numberChanged(bool bIncremented)102 ParagraphImpl::numberChanged(bool bIncremented)
103 {
104 if (bIncremented)
105 ++m_nNumber;
106 else
107 --m_nNumber;
108 }
109
textChanged()110 void ParagraphImpl::textChanged()
111 {
112 ::rtl::OUString aParagraphText = implGetText();
113 ::css::uno::Any aOldValue, aNewValue;
114 if ( implInitTextChangedEvent( m_aParagraphText, aParagraphText, aOldValue, aNewValue ) )
115 {
116 m_aParagraphText = aParagraphText;
117 notifyEvent(::css::accessibility::AccessibleEventId::
118 TEXT_CHANGED,
119 aOldValue, aNewValue);
120 }
121 }
122
notifyEvent(::sal_Int16 nEventId,::css::uno::Any const & rOldValue,::css::uno::Any const & rNewValue)123 void ParagraphImpl::notifyEvent(::sal_Int16 nEventId,
124 ::css::uno::Any const & rOldValue,
125 ::css::uno::Any const & rNewValue)
126 {
127 if (m_nClientId)
128 comphelper::AccessibleEventNotifier::addEvent( m_nClientId, ::css::accessibility::AccessibleEventObject(
129 static_cast< ::cppu::OWeakObject * >(this),
130 nEventId, rNewValue, rOldValue) );
131 }
132
133 // virtual
134 ::css::uno::Reference< ::css::accessibility::XAccessibleContext > SAL_CALL
getAccessibleContext()135 ParagraphImpl::getAccessibleContext()
136 {
137 checkDisposed();
138 return this;
139 }
140
141 // virtual
getAccessibleChildCount()142 ::sal_Int32 SAL_CALL ParagraphImpl::getAccessibleChildCount()
143 {
144 checkDisposed();
145 return 0;
146 }
147
148 // virtual
149 ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL
getAccessibleChild(::sal_Int32)150 ParagraphImpl::getAccessibleChild(::sal_Int32)
151 {
152 checkDisposed();
153 throw ::css::lang::IndexOutOfBoundsException(
154 ::rtl::OUString(
155 RTL_CONSTASCII_USTRINGPARAM(
156 "textwindowaccessibility.cxx:"
157 " ParagraphImpl::getAccessibleChild")),
158 static_cast< ::css::uno::XWeak * >(this));
159 }
160
161 // virtual
162 ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL
getAccessibleParent()163 ParagraphImpl::getAccessibleParent()
164 {
165 checkDisposed();
166 return m_xDocument->getAccessible();
167 }
168
169 // virtual
getAccessibleIndexInParent()170 ::sal_Int32 SAL_CALL ParagraphImpl::getAccessibleIndexInParent()
171 {
172 checkDisposed();
173 return m_xDocument->retrieveParagraphIndex(this);
174 }
175
176 // virtual
getAccessibleRole()177 ::sal_Int16 SAL_CALL ParagraphImpl::getAccessibleRole()
178 {
179 checkDisposed();
180 return ::css::accessibility::AccessibleRole::PARAGRAPH;
181 }
182
183 // virtual
getAccessibleDescription()184 ::rtl::OUString SAL_CALL ParagraphImpl::getAccessibleDescription()
185 {
186 checkDisposed();
187 return ::rtl::OUString();
188 }
189
190 // virtual
getAccessibleName()191 ::rtl::OUString SAL_CALL ParagraphImpl::getAccessibleName()
192 {
193 checkDisposed();
194 return ::rtl::OUString();
195 }
196
197 // virtual
198 ::css::uno::Reference< ::css::accessibility::XAccessibleRelationSet >
getAccessibleRelationSet()199 SAL_CALL ParagraphImpl::getAccessibleRelationSet()
200 {
201 checkDisposed();
202 return m_xDocument->retrieveParagraphRelationSet( this );
203 }
204
205 // virtual
206 ::css::uno::Reference< ::css::accessibility::XAccessibleStateSet >
getAccessibleStateSet()207 SAL_CALL ParagraphImpl::getAccessibleStateSet()
208 {
209 checkDisposed();
210
211 // FIXME Notification of changes (STATE_CHANGED) missing when
212 // m_rView.IsReadOnly() changes:
213 return new ::utl::AccessibleStateSetHelper(
214 m_xDocument->retrieveParagraphState(this));
215 }
216
217 // virtual
getLocale()218 ::css::lang::Locale SAL_CALL ParagraphImpl::getLocale()
219 {
220 checkDisposed();
221 return m_xDocument->retrieveLocale();
222 }
223
224 // virtual
containsPoint(::css::awt::Point const & rPoint)225 ::sal_Bool SAL_CALL ParagraphImpl::containsPoint(::css::awt::Point const & rPoint)
226 {
227 checkDisposed();
228 ::css::awt::Rectangle aRect(m_xDocument->retrieveParagraphBounds(this,
229 false));
230 return rPoint.X >= 0 && rPoint.X < aRect.Width
231 && rPoint.Y >= 0 && rPoint.Y < aRect.Height;
232 }
233
234 // virtual
235 ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL
getAccessibleAtPoint(::css::awt::Point const &)236 ParagraphImpl::getAccessibleAtPoint(::css::awt::Point const &)
237 {
238 checkDisposed();
239 return 0;
240 }
241
242 // virtual
getBounds()243 ::css::awt::Rectangle SAL_CALL ParagraphImpl::getBounds()
244 {
245 checkDisposed();
246 return m_xDocument->retrieveParagraphBounds(this, false);
247 }
248
249 // virtual
getLocation()250 ::css::awt::Point SAL_CALL ParagraphImpl::getLocation()
251 {
252 checkDisposed();
253 ::css::awt::Rectangle aRect(m_xDocument->retrieveParagraphBounds(this,
254 false));
255 return ::css::awt::Point(aRect.X, aRect.Y);
256 }
257
258 // virtual
getLocationOnScreen()259 ::css::awt::Point SAL_CALL ParagraphImpl::getLocationOnScreen()
260 {
261 checkDisposed();
262 ::css::awt::Rectangle aRect(m_xDocument->retrieveParagraphBounds(this,
263 true));
264 return ::css::awt::Point(aRect.X, aRect.Y);
265 }
266
267 // virtual
getSize()268 ::css::awt::Size SAL_CALL ParagraphImpl::getSize()
269 {
270 checkDisposed();
271 ::css::awt::Rectangle aRect(m_xDocument->retrieveParagraphBounds(this,
272 false));
273 return ::css::awt::Size(aRect.Width, aRect.Height);
274 }
275
276 // virtual
grabFocus()277 void SAL_CALL ParagraphImpl::grabFocus()
278 {
279 checkDisposed();
280 Window* pWindow = m_xDocument->GetWindow();
281 if ( pWindow )
282 {
283 pWindow->GrabFocus();
284 }
285 try
286 {
287 m_xDocument->changeParagraphSelection(this, 0, 0);
288 }
289 catch (::css::lang::IndexOutOfBoundsException & rEx)
290 {
291 OSL_TRACE(
292 "textwindowaccessibility.cxx: ParagraphImpl::grabFocus:"
293 " caught unexpected %s\n",
294 ::rtl::OUStringToOString(rEx.Message, RTL_TEXTENCODING_UTF8).
295 getStr());
296 }
297 }
298
299 // virtual
getAccessibleKeyBinding()300 ::css::uno::Any SAL_CALL ParagraphImpl::getAccessibleKeyBinding()
301 {
302 checkDisposed();
303 return ::css::uno::Any();
304 }
305
306 // virtual
getForeground()307 ::css::util::Color SAL_CALL ParagraphImpl::getForeground()
308 {
309 return 0; // TODO
310 }
311
312 // virtual
getBackground()313 ::css::util::Color SAL_CALL ParagraphImpl::getBackground()
314 {
315 return 0; // TODO
316 }
317
318 // virtual
getCaretPosition()319 ::sal_Int32 SAL_CALL ParagraphImpl::getCaretPosition()
320 {
321 checkDisposed();
322 return m_xDocument->retrieveParagraphCaretPosition(this);
323 }
324
325 // virtual
setCaretPosition(::sal_Int32 nIndex)326 ::sal_Bool SAL_CALL ParagraphImpl::setCaretPosition(::sal_Int32 nIndex)
327 {
328 checkDisposed();
329 m_xDocument->changeParagraphSelection(this, nIndex, nIndex);
330 return true;
331 }
332
333 // virtual
getCharacter(::sal_Int32 nIndex)334 ::sal_Unicode SAL_CALL ParagraphImpl::getCharacter(::sal_Int32 nIndex)
335 {
336 checkDisposed();
337 return OCommonAccessibleText::getCharacter(nIndex);
338 }
339
340 // virtual
341 ::css::uno::Sequence< ::css::beans::PropertyValue > SAL_CALL
getCharacterAttributes(::sal_Int32 nIndex,const::com::sun::star::uno::Sequence<::rtl::OUString> & aRequestedAttributes)342 ParagraphImpl::getCharacterAttributes(::sal_Int32 nIndex, const ::com::sun::star::uno::Sequence< ::rtl::OUString >& aRequestedAttributes)
343 {
344 checkDisposed();
345 return m_xDocument->retrieveCharacterAttributes( this, nIndex, aRequestedAttributes );
346 }
347
348 // virtual
349 ::css::awt::Rectangle SAL_CALL
getCharacterBounds(::sal_Int32 nIndex)350 ParagraphImpl::getCharacterBounds(::sal_Int32 nIndex)
351 {
352 checkDisposed();
353 ::css::awt::Rectangle aBounds(m_xDocument->retrieveCharacterBounds(this, nIndex));
354 ::css::awt::Rectangle aParaBounds(m_xDocument->retrieveParagraphBounds(this, false));
355 aBounds.X -= aParaBounds.X;
356 aBounds.Y -= aParaBounds.Y;
357 return aBounds;
358 }
359
360 // virtual
getCharacterCount()361 ::sal_Int32 SAL_CALL ParagraphImpl::getCharacterCount()
362 {
363 checkDisposed();
364 return OCommonAccessibleText::getCharacterCount();
365 }
366
367 // virtual
368 ::sal_Int32 SAL_CALL
getIndexAtPoint(::css::awt::Point const & rPoint)369 ParagraphImpl::getIndexAtPoint(::css::awt::Point const & rPoint)
370 {
371 checkDisposed();
372 ::css::awt::Point aPoint(rPoint);
373 ::css::awt::Rectangle aParaBounds(m_xDocument->retrieveParagraphBounds(this, false));
374 aPoint.X += aParaBounds.X;
375 aPoint.Y += aParaBounds.Y;
376 return m_xDocument->retrieveCharacterIndex(this, aPoint);
377 }
378
379 // virtual
getSelectedText()380 ::rtl::OUString SAL_CALL ParagraphImpl::getSelectedText()
381 {
382 checkDisposed();
383
384 return OCommonAccessibleText::getSelectedText();
385 }
386
387 // virtual
getSelectionStart()388 ::sal_Int32 SAL_CALL ParagraphImpl::getSelectionStart()
389 {
390 checkDisposed();
391 return OCommonAccessibleText::getSelectionStart();
392 }
393
394 // virtual
getSelectionEnd()395 ::sal_Int32 SAL_CALL ParagraphImpl::getSelectionEnd()
396 {
397 checkDisposed();
398 return OCommonAccessibleText::getSelectionEnd();
399 }
400
401 // virtual
setSelection(::sal_Int32 nStartIndex,::sal_Int32 nEndIndex)402 ::sal_Bool SAL_CALL ParagraphImpl::setSelection(::sal_Int32 nStartIndex,
403 ::sal_Int32 nEndIndex)
404 {
405 checkDisposed();
406 m_xDocument->changeParagraphSelection(this, nStartIndex, nEndIndex);
407 return true;
408 }
409
410 // virtual
getText()411 ::rtl::OUString SAL_CALL ParagraphImpl::getText()
412 {
413 checkDisposed();
414 return OCommonAccessibleText::getText();
415 }
416
417 // virtual
getTextRange(::sal_Int32 nStartIndex,::sal_Int32 nEndIndex)418 ::rtl::OUString SAL_CALL ParagraphImpl::getTextRange(::sal_Int32 nStartIndex,
419 ::sal_Int32 nEndIndex)
420 {
421 checkDisposed();
422 return OCommonAccessibleText::getTextRange(nStartIndex, nEndIndex);
423 }
424
425 // virtual
getTextAtIndex(sal_Int32 nIndex,sal_Int16 aTextType)426 ::com::sun::star::accessibility::TextSegment SAL_CALL ParagraphImpl::getTextAtIndex( sal_Int32 nIndex, sal_Int16 aTextType )
427 {
428 checkDisposed();
429 return OCommonAccessibleText::getTextAtIndex(nIndex, aTextType);
430 }
431
432 // virtual
getTextBeforeIndex(sal_Int32 nIndex,sal_Int16 aTextType)433 ::com::sun::star::accessibility::TextSegment SAL_CALL ParagraphImpl::getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 aTextType )
434 {
435 checkDisposed();
436 return OCommonAccessibleText::getTextBeforeIndex(nIndex, aTextType);
437 }
438
439 // virtual
getTextBehindIndex(sal_Int32 nIndex,sal_Int16 aTextType)440 ::com::sun::star::accessibility::TextSegment SAL_CALL ParagraphImpl::getTextBehindIndex( sal_Int32 nIndex, sal_Int16 aTextType )
441 {
442 checkDisposed();
443 return OCommonAccessibleText::getTextBehindIndex(nIndex, aTextType);
444 }
445
446 // virtual
copyText(::sal_Int32 nStartIndex,::sal_Int32 nEndIndex)447 ::sal_Bool SAL_CALL ParagraphImpl::copyText(::sal_Int32 nStartIndex,
448 ::sal_Int32 nEndIndex)
449 {
450 checkDisposed();
451 m_xDocument->copyParagraphText(this, nStartIndex, nEndIndex);
452 return true;
453 }
454
455 // virtual
cutText(::sal_Int32 nStartIndex,::sal_Int32 nEndIndex)456 ::sal_Bool SAL_CALL ParagraphImpl::cutText(::sal_Int32 nStartIndex,
457 ::sal_Int32 nEndIndex)
458 {
459 checkDisposed();
460 m_xDocument->changeParagraphText(this, nStartIndex, nEndIndex, true, false,
461 ::rtl::OUString());
462 return true;
463 }
464
465 // virtual
pasteText(::sal_Int32 nIndex)466 ::sal_Bool SAL_CALL ParagraphImpl::pasteText(::sal_Int32 nIndex)
467 {
468 checkDisposed();
469 m_xDocument->changeParagraphText(this, nIndex, nIndex, false, true,
470 ::rtl::OUString());
471 return true;
472 }
473
474 // virtual
deleteText(::sal_Int32 nStartIndex,::sal_Int32 nEndIndex)475 ::sal_Bool SAL_CALL ParagraphImpl::deleteText(::sal_Int32 nStartIndex,
476 ::sal_Int32 nEndIndex)
477 {
478 checkDisposed();
479 m_xDocument->changeParagraphText(this, nStartIndex, nEndIndex, false, false,
480 ::rtl::OUString());
481 return true;
482 }
483
484 // virtual
insertText(::rtl::OUString const & rText,::sal_Int32 nIndex)485 ::sal_Bool SAL_CALL ParagraphImpl::insertText(::rtl::OUString const & rText,
486 ::sal_Int32 nIndex)
487 {
488 checkDisposed();
489 m_xDocument->changeParagraphText(this, nIndex, nIndex, false, false, rText);
490 return true;
491 }
492
493 // virtual
494 ::sal_Bool SAL_CALL
replaceText(::sal_Int32 nStartIndex,::sal_Int32 nEndIndex,::rtl::OUString const & rReplacement)495 ParagraphImpl::replaceText(::sal_Int32 nStartIndex, ::sal_Int32 nEndIndex,
496 ::rtl::OUString const & rReplacement)
497 {
498 checkDisposed();
499 m_xDocument->changeParagraphText(this, nStartIndex, nEndIndex, false, false,
500 rReplacement);
501 return true;
502 }
503
504 // virtual
setAttributes(::sal_Int32 nStartIndex,::sal_Int32 nEndIndex,::css::uno::Sequence<::css::beans::PropertyValue> const & rAttributeSet)505 ::sal_Bool SAL_CALL ParagraphImpl::setAttributes(
506 ::sal_Int32 nStartIndex, ::sal_Int32 nEndIndex,
507 ::css::uno::Sequence< ::css::beans::PropertyValue > const & rAttributeSet)
508 {
509 checkDisposed();
510 m_xDocument->changeParagraphAttributes(this, nStartIndex, nEndIndex,
511 rAttributeSet);
512 return true;
513 }
514
515 // virtual
setText(::rtl::OUString const & rText)516 ::sal_Bool SAL_CALL ParagraphImpl::setText(::rtl::OUString const & rText)
517 {
518 checkDisposed();
519 m_xDocument->changeParagraphText(this, rText);
520 return true;
521 }
522
523 // virtual
524 ::css::uno::Sequence< ::css::beans::PropertyValue > SAL_CALL
getDefaultAttributes(const::css::uno::Sequence<::rtl::OUString> & RequestedAttributes)525 ParagraphImpl::getDefaultAttributes(const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes)
526 {
527 checkDisposed();
528 return m_xDocument->retrieveDefaultAttributes( this, RequestedAttributes );
529 }
530
531 // virtual
532 ::css::uno::Sequence< ::css::beans::PropertyValue > SAL_CALL
getRunAttributes(::sal_Int32 Index,const::css::uno::Sequence<::rtl::OUString> & RequestedAttributes)533 ParagraphImpl::getRunAttributes(::sal_Int32 Index, const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes)
534 {
535 checkDisposed();
536 return m_xDocument->retrieveRunAttributes( this, Index, RequestedAttributes );
537 }
538
539 // virtual
getLineNumberAtIndex(::sal_Int32 nIndex)540 ::sal_Int32 SAL_CALL ParagraphImpl::getLineNumberAtIndex( ::sal_Int32 nIndex )
541 {
542 checkDisposed();
543
544 ::sal_Int32 nLineNo = -1;
545 ::css::i18n::Boundary aBoundary =
546 m_xDocument->retrieveParagraphLineBoundary( this, nIndex, &nLineNo );
547
548 return nLineNo;
549 }
550
551 // virtual
getTextAtLineNumber(::sal_Int32 nLineNo)552 ::css::accessibility::TextSegment SAL_CALL ParagraphImpl::getTextAtLineNumber( ::sal_Int32 nLineNo )
553 {
554 checkDisposed();
555
556 ::css::i18n::Boundary aBoundary =
557 m_xDocument->retrieveParagraphBoundaryOfLine( this, nLineNo );
558
559 return ::css::accessibility::TextSegment( getTextRange(aBoundary.startPos, aBoundary.endPos),
560 aBoundary.startPos, aBoundary.endPos);
561 }
562
563 // virtual
getTextAtLineWithCaret()564 ::css::accessibility::TextSegment SAL_CALL ParagraphImpl::getTextAtLineWithCaret( )
565 {
566 checkDisposed();
567
568 sal_Int32 nLineNo = getNumberOfLineWithCaret();
569
570 try {
571 return ( nLineNo >= 0 ) ?
572 getTextAtLineNumber( nLineNo ) :
573 ::css::accessibility::TextSegment();
574 } catch (const ::css::lang::IndexOutOfBoundsException&) {
575 throw ::css::uno::RuntimeException(
576 ::rtl::OUString(
577 RTL_CONSTASCII_USTRINGPARAM(
578 "textwindowaccessibility.cxx:"
579 " ParagraphImpl::getTextAtLineWithCaret") ),
580 static_cast< ::css::uno::XWeak * >( this ) );
581 }
582 }
583
584 // virtual
getNumberOfLineWithCaret()585 ::sal_Int32 SAL_CALL ParagraphImpl::getNumberOfLineWithCaret( )
586 {
587 checkDisposed();
588 return m_xDocument->retrieveParagraphLineWithCursor(this);
589 }
590
591
592 // virtual
addEventListener(::css::uno::Reference<::css::accessibility::XAccessibleEventListener> const & rListener)593 void SAL_CALL ParagraphImpl::addEventListener(
594 ::css::uno::Reference<
595 ::css::accessibility::XAccessibleEventListener > const & rListener)
596 {
597 if (rListener.is())
598 {
599 ::osl::ClearableMutexGuard aGuard(rBHelper.rMutex);
600 if (rBHelper.bDisposed || rBHelper.bInDispose)
601 {
602 aGuard.clear();
603 rListener->disposing(::css::lang::EventObject(
604 static_cast< ::cppu::OWeakObject * >(this)));
605 }
606 else
607 {
608 if (!m_nClientId)
609 m_nClientId = comphelper::AccessibleEventNotifier::registerClient( );
610 comphelper::AccessibleEventNotifier::addEventListener( m_nClientId, rListener );
611 }
612 }
613 }
614
615 // virtual
removeEventListener(::css::uno::Reference<::css::accessibility::XAccessibleEventListener> const & rListener)616 void SAL_CALL ParagraphImpl::removeEventListener(
617 ::css::uno::Reference<
618 ::css::accessibility::XAccessibleEventListener > const & rListener)
619 {
620 comphelper::AccessibleEventNotifier::TClientId nId = 0;
621 {
622 ::osl::ClearableMutexGuard aGuard(rBHelper.rMutex);
623 if (rListener.is() && m_nClientId != 0
624 && comphelper::AccessibleEventNotifier::removeEventListener( m_nClientId, rListener ) == 0)
625 {
626 nId = m_nClientId;
627 m_nClientId = 0;
628 }
629 }
630 if (nId != 0)
631 {
632 // no listeners anymore
633 // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
634 // and at least to us not firing any events anymore, in case somebody calls
635 // NotifyAccessibleEvent, again
636 comphelper::AccessibleEventNotifier::revokeClient(nId);
637 }
638 }
639
640 // virtual
disposing()641 void SAL_CALL ParagraphImpl::disposing()
642 {
643 comphelper::AccessibleEventNotifier::TClientId nId = 0;
644 {
645 ::osl::ClearableMutexGuard aGuard(rBHelper.rMutex);
646 nId = m_nClientId;
647 m_nClientId = 0;
648 }
649 if (nId != 0)
650 comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing(nId, *this);
651 }
652
653 // virtual
implGetText()654 ::rtl::OUString ParagraphImpl::implGetText()
655 {
656 return m_xDocument->retrieveParagraphText(this);
657 }
658
659 // virtual
implGetLocale()660 ::css::lang::Locale ParagraphImpl::implGetLocale()
661 {
662 return m_xDocument->retrieveLocale();
663 }
664
665 // virtual
implGetSelection(::sal_Int32 & rStartIndex,::sal_Int32 & rEndIndex)666 void ParagraphImpl::implGetSelection(::sal_Int32 & rStartIndex,
667 ::sal_Int32 & rEndIndex)
668 {
669 m_xDocument->retrieveParagraphSelection(this, &rStartIndex, &rEndIndex);
670 }
671
672 // virtual
implGetParagraphBoundary(::css::i18n::Boundary & rBoundary,::sal_Int32 nIndex)673 void ParagraphImpl::implGetParagraphBoundary( ::css::i18n::Boundary& rBoundary,
674 ::sal_Int32 nIndex )
675 {
676 ::rtl::OUString sText( implGetText() );
677 ::sal_Int32 nLength = sText.getLength();
678
679 if ( implIsValidIndex( nIndex, nLength ) )
680 {
681 rBoundary.startPos = 0;
682 rBoundary.endPos = nLength;
683 }
684 else
685 {
686 rBoundary.startPos = nIndex;
687 rBoundary.endPos = nIndex;
688 }
689 }
690
691 // virtual
implGetLineBoundary(::css::i18n::Boundary & rBoundary,::sal_Int32 nIndex)692 void ParagraphImpl::implGetLineBoundary( ::css::i18n::Boundary& rBoundary,
693 ::sal_Int32 nIndex )
694 {
695 ::rtl::OUString sText( implGetText() );
696 ::sal_Int32 nLength = sText.getLength();
697
698 if ( implIsValidIndex( nIndex, nLength ) || nIndex == nLength )
699 {
700 ::css::i18n::Boundary aBoundary =
701 m_xDocument->retrieveParagraphLineBoundary( this, nIndex );
702 rBoundary.startPos = aBoundary.startPos;
703 rBoundary.endPos = aBoundary.endPos;
704 }
705 else
706 {
707 rBoundary.startPos = nIndex;
708 rBoundary.endPos = nIndex;
709 }
710 }
711
712
checkDisposed()713 void ParagraphImpl::checkDisposed()
714 {
715 ::osl::MutexGuard aGuard(rBHelper.rMutex);
716 if (!(rBHelper.bDisposed || rBHelper.bInDispose))
717 return;
718 throw ::css::lang::DisposedException(
719 ::rtl::OUString(), static_cast< ::css::uno::XWeak * >(this));
720 }
721
Document(::VCLXWindow * pVclXWindow,::TextEngine & rEngine,::TextView & rView,bool bCompoundControlChild)722 Document::Document(::VCLXWindow * pVclXWindow, ::TextEngine & rEngine,
723 ::TextView & rView, bool bCompoundControlChild):
724 VCLXAccessibleComponent(pVclXWindow),
725 m_xAccessible(pVclXWindow),
726 m_rEngine(rEngine),
727 m_rView(rView),
728 m_aEngineListener(*this),
729 m_aViewListener(LINK(this, Document, WindowEventHandler)),
730 m_bCompoundControlChild(bCompoundControlChild)
731 {}
732
retrieveLocale()733 ::css::lang::Locale Document::retrieveLocale()
734 {
735 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
736 return m_rEngine.GetLocale();
737 }
738
retrieveParagraphIndex(ParagraphImpl const * pParagraph)739 ::sal_Int32 Document::retrieveParagraphIndex(ParagraphImpl const * pParagraph)
740 {
741 ::osl::MutexGuard aInternalGuard(GetMutex());
742
743 // If a client holds on to a Paragraph that is no longer visible, it can
744 // happen that this Paragraph lies outside the range from m_aVisibleBegin
745 // to m_aVisibleEnd. In that case, return -1 instead of a valid index:
746 Paragraphs::iterator aPara(m_xParagraphs->begin()
747 + pParagraph->getNumber());
748 return aPara < m_aVisibleBegin || aPara >= m_aVisibleEnd
749 ? -1 : static_cast< ::sal_Int32 >(aPara - m_aVisibleBegin);
750 // XXX numeric overflow
751 }
752
retrieveParagraphState(ParagraphImpl const * pParagraph)753 ::sal_Int64 Document::retrieveParagraphState(ParagraphImpl const * pParagraph)
754 {
755 ::osl::MutexGuard aInternalGuard(GetMutex());
756
757 // If a client holds on to a Paragraph that is no longer visible, it can
758 // happen that this Paragraph lies outside the range from m_aVisibleBegin
759 // to m_aVisibleEnd. In that case, it is neither VISIBLE nor SHOWING:
760 ::sal_Int64 nState
761 = (static_cast< ::sal_Int64 >(1)
762 << ::css::accessibility::AccessibleStateType::ENABLED)
763 | (static_cast< ::sal_Int64 >(1)
764 << ::css::accessibility::AccessibleStateType::SENSITIVE)
765 | (static_cast< ::sal_Int64 >(1)
766 << ::css::accessibility::AccessibleStateType::FOCUSABLE)
767 | (static_cast< ::sal_Int64 >(1)
768 << ::css::accessibility::AccessibleStateType::MULTI_LINE);
769 if (!m_rView.IsReadOnly())
770 nState |= (static_cast< ::sal_Int64 >(1)
771 << ::css::accessibility::AccessibleStateType::EDITABLE);
772 Paragraphs::iterator aPara(m_xParagraphs->begin()
773 + pParagraph->getNumber());
774 if (aPara >= m_aVisibleBegin && aPara < m_aVisibleEnd)
775 {
776 nState
777 |= (static_cast< ::sal_Int64 >(1)
778 << ::css::accessibility::AccessibleStateType::VISIBLE)
779 | (static_cast< ::sal_Int64 >(1)
780 << ::css::accessibility::AccessibleStateType::SHOWING);
781 if (aPara == m_aFocused)
782 nState |= (static_cast< ::sal_Int64 >(1)
783 << ::css::accessibility::AccessibleStateType::FOCUSED);
784 }
785 return nState;
786 };
787
788 ::css::awt::Rectangle
retrieveParagraphBounds(ParagraphImpl const * pParagraph,bool bAbsolute)789 Document::retrieveParagraphBounds(ParagraphImpl const * pParagraph,
790 bool bAbsolute)
791 {
792 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
793 ::osl::MutexGuard aInternalGuard(GetMutex());
794
795 // If a client holds on to a Paragraph that is no longer visible (as it
796 // scrolled out the top of the view), it can happen that this Paragraph
797 // lies before m_aVisibleBegin. In that case, calculate the vertical
798 // position of the Paragraph starting at paragraph 0, otherwise optimize
799 // and start at m_aVisibleBegin:
800 Paragraphs::iterator aPara(m_xParagraphs->begin()
801 + pParagraph->getNumber());
802 ::sal_Int32 nPos;
803 Paragraphs::iterator aIt;
804 if (aPara < m_aVisibleBegin)
805 {
806 nPos = 0;
807 aIt = m_xParagraphs->begin();
808 }
809 else
810 {
811 nPos = m_nViewOffset - m_nVisibleBeginOffset;
812 aIt = m_aVisibleBegin;
813 }
814 for (; aIt != aPara; ++aIt)
815 nPos += aIt->getHeight();
816
817 Point aOrig(0, 0);
818 if (bAbsolute)
819 aOrig = m_rView.GetWindow()->OutputToAbsoluteScreenPixel(aOrig);
820
821 return ::css::awt::Rectangle(
822 static_cast< ::sal_Int32 >(aOrig.X()),
823 static_cast< ::sal_Int32 >(aOrig.Y()) + nPos - m_nViewOffset,
824 m_rView.GetWindow()->GetOutputSizePixel().Width(), aPara->getHeight());
825 // XXX numeric overflow (3x)
826 }
827
828 ::rtl::OUString
retrieveParagraphText(ParagraphImpl const * pParagraph)829 Document::retrieveParagraphText(ParagraphImpl const * pParagraph)
830 {
831 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
832 ::osl::MutexGuard aInternalGuard(GetMutex());
833 return m_rEngine.GetText(static_cast< ::sal_uLong >(pParagraph->getNumber()));
834 // numeric overflow cannot happen here
835 }
836
retrieveParagraphSelection(ParagraphImpl const * pParagraph,::sal_Int32 * pBegin,::sal_Int32 * pEnd)837 void Document::retrieveParagraphSelection(ParagraphImpl const * pParagraph,
838 ::sal_Int32 * pBegin,
839 ::sal_Int32 * pEnd)
840 {
841 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
842 ::osl::MutexGuard aInternalGuard(GetMutex());
843 ::TextSelection const & rSelection = m_rView.GetSelection();
844 Paragraphs::size_type nNumber = pParagraph->getNumber();
845 TextPaM aStartPaM( rSelection.GetStart() );
846 TextPaM aEndPaM( rSelection.GetEnd() );
847 TextPaM aMinPaM( ::std::min( aStartPaM, aEndPaM ) );
848 TextPaM aMaxPaM( ::std::max( aStartPaM, aEndPaM ) );
849
850 if ( nNumber >= aMinPaM.GetPara() && nNumber <= aMaxPaM.GetPara() )
851 {
852 *pBegin = nNumber > aMinPaM.GetPara()
853 ? 0
854 : static_cast< ::sal_Int32 >( aMinPaM.GetIndex() );
855 // XXX numeric overflow
856 *pEnd = nNumber < aMaxPaM.GetPara()
857 ? static_cast< ::sal_Int32 >( m_rEngine.GetText(static_cast< ::sal_uLong >(nNumber)).Len() )
858 : static_cast< ::sal_Int32 >( aMaxPaM.GetIndex() );
859 // XXX numeric overflow (3x)
860
861 if ( aStartPaM > aEndPaM )
862 ::std::swap( *pBegin, *pEnd );
863 }
864 else
865 {
866 *pBegin = 0;
867 *pEnd = 0;
868 }
869 }
870
retrieveParagraphCaretPosition(ParagraphImpl const * pParagraph)871 ::sal_Int32 Document::retrieveParagraphCaretPosition(ParagraphImpl const * pParagraph)
872 {
873 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
874 ::osl::MutexGuard aInternalGuard(GetMutex());
875 ::TextSelection const & rSelection = m_rView.GetSelection();
876 Paragraphs::size_type nNumber = pParagraph->getNumber();
877 TextPaM aEndPaM( rSelection.GetEnd() );
878
879 return aEndPaM.GetPara() == nNumber
880 ? static_cast< ::sal_Int32 >(aEndPaM.GetIndex()) : -1;
881 }
882
883 ::css::awt::Rectangle
retrieveCharacterBounds(ParagraphImpl const * pParagraph,::sal_Int32 nIndex)884 Document::retrieveCharacterBounds(ParagraphImpl const * pParagraph,
885 ::sal_Int32 nIndex)
886 {
887 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
888 ::osl::MutexGuard aInternalGuard(GetMutex());
889 ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber());
890 sal_Int32 nLength = m_rEngine.GetText(nNumber).Len();
891 // XXX numeric overflow
892 if (nIndex < 0 || nIndex > nLength)
893 throw ::css::lang::IndexOutOfBoundsException(
894 ::rtl::OUString(
895 RTL_CONSTASCII_USTRINGPARAM(
896 "textwindowaccessibility.cxx:"
897 " Document::retrieveCharacterAttributes")),
898 static_cast< ::css::uno::XWeak * >(this));
899 ::css::awt::Rectangle aBounds( 0, 0, 0, 0 );
900 if ( nIndex == nLength )
901 {
902 aBounds = AWTRectangle(
903 m_rEngine.PaMtoEditCursor(::TextPaM(nNumber,
904 static_cast< ::sal_uInt16 >(nIndex))));
905 }
906 else
907 {
908 ::Rectangle aLeft(
909 m_rEngine.PaMtoEditCursor(::TextPaM(nNumber,
910 static_cast< ::sal_uInt16 >(nIndex))));
911 // XXX numeric overflow
912 ::Rectangle aRight(
913 m_rEngine.PaMtoEditCursor(::TextPaM(nNumber,
914 static_cast< ::sal_uInt16 >(nIndex)
915 + 1)));
916 // XXX numeric overflow (2x)
917 // FIXME If the vertical extends of the two cursors do not match, assume
918 // nIndex is the last character on the line; the bounding box will then
919 // extend to m_rEnginge.GetMaxTextWidth():
920 ::sal_Int32 nWidth = (aLeft.Top() == aRight.Top()
921 && aLeft.Bottom() == aRight.Bottom())
922 ? static_cast< ::sal_Int32 >(aRight.Left() - aLeft.Left())
923 : static_cast< ::sal_Int32 >(m_rEngine.GetMaxTextWidth()
924 - aLeft.Left());
925 // XXX numeric overflow (4x)
926 aBounds = ::css::awt::Rectangle(static_cast< ::sal_Int32 >(aLeft.Left()),
927 static_cast< ::sal_Int32 >(aLeft.Top() - m_nViewOffset),
928 nWidth,
929 static_cast< ::sal_Int32 >(aLeft.Bottom()
930 - aLeft.Top()));
931 // XXX numeric overflow (4x)
932 }
933 return aBounds;
934 }
935
retrieveCharacterIndex(ParagraphImpl const * pParagraph,::css::awt::Point const & rPoint)936 ::sal_Int32 Document::retrieveCharacterIndex(ParagraphImpl const * pParagraph,
937 ::css::awt::Point const & rPoint)
938 {
939 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
940 ::osl::MutexGuard aInternalGuard(GetMutex());
941 ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber());
942 // XXX numeric overflow
943 ::TextPaM aPaM(m_rEngine.GetPaM(::Point(static_cast< long >(rPoint.X),
944 static_cast< long >(rPoint.Y))));
945 // XXX numeric overflow (2x)
946 return aPaM.GetPara() == nNumber
947 ? static_cast< ::sal_Int32 >(aPaM.GetIndex()) : -1;
948 // XXX numeric overflow
949 }
950
951 struct IndexCompare
952 {
953 const ::css::beans::PropertyValue* pValues;
IndexCompareaccessibility::IndexCompare954 IndexCompare( const ::css::beans::PropertyValue* pVals ) : pValues(pVals) {}
operator ()accessibility::IndexCompare955 bool operator() ( const sal_Int32& a, const sal_Int32& b ) const
956 {
957 return (pValues[a].Name < pValues[b].Name) ? true : false;
958 }
959 };
960
961 ::css::uno::Sequence< ::css::beans::PropertyValue >
retrieveCharacterAttributes(ParagraphImpl const * pParagraph,::sal_Int32 nIndex,const::css::uno::Sequence<::rtl::OUString> & aRequestedAttributes)962 Document::retrieveCharacterAttributes(
963 ParagraphImpl const * pParagraph, ::sal_Int32 nIndex,
964 const ::css::uno::Sequence< ::rtl::OUString >& aRequestedAttributes)
965 {
966 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
967
968 Font aFont = m_rEngine.GetFont();
969 const sal_Int32 AttributeCount = 9;
970 sal_Int32 i = 0;
971 ::css::uno::Sequence< ::css::beans::PropertyValue > aAttribs( AttributeCount );
972 //character background color
973 {
974 aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharBackColor"));
975 aAttribs[i].Handle = -1;
976 aAttribs[i].Value = mapFontColor( aFont.GetFillColor() );
977 aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE;
978 i++;
979 }
980 //character color
981 {
982 aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharColor"));
983 aAttribs[i].Handle = -1;
984 //aAttribs[i].Value = mapFontColor( aFont.GetColor() );
985 aAttribs[i].Value = mapFontColor( m_rEngine.GetTextColor() );
986 aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE;
987 i++;
988 }
989 //character font name
990 {
991 aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharFontName"));
992 aAttribs[i].Handle = -1;
993 aAttribs[i].Value = ::css::uno::makeAny( (::rtl::OUString)aFont.GetName() );
994 aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE;
995 i++;
996 }
997 //character height
998 {
999 aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharHeight"));
1000 aAttribs[i].Handle = -1;
1001 aAttribs[i].Value = ::css::uno::makeAny( (sal_Int16)aFont.GetHeight() );
1002 aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE;
1003 i++;
1004 }
1005 //character posture
1006 {
1007 aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharPosture"));
1008 aAttribs[i].Handle = -1;
1009 aAttribs[i].Value = ::css::uno::makeAny( (sal_Int16)aFont.GetItalic() );
1010 aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE;
1011 i++;
1012 }
1013 //character relief
1014 /*{
1015 aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharRelief"));
1016 aAttribs[i].Handle = -1;
1017 aAttribs[i].Value = ::css::uno::makeAny( (sal_Int16)aFont.GetRelief() );
1018 aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE;
1019 i++;
1020 }*/
1021 //character strikeout
1022 {
1023 aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharStrikeout"));
1024 aAttribs[i].Handle = -1;
1025 aAttribs[i].Value = ::css::uno::makeAny( (sal_Int16)aFont.GetStrikeout() );
1026 aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE;
1027 i++;
1028 }
1029 //character underline
1030 {
1031 aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharUnderline"));
1032 aAttribs[i].Handle = -1;
1033 aAttribs[i].Value = ::css::uno::makeAny( (sal_Int16)aFont.GetUnderline() );
1034 aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE;
1035 i++;
1036 }
1037 //character weight
1038 {
1039 aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharWeight"));
1040 aAttribs[i].Handle = -1;
1041 aAttribs[i].Value = ::css::uno::makeAny( (float)aFont.GetWeight() );
1042 aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE;
1043 i++;
1044 }
1045 //character alignment
1046 {
1047 aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ParaAdjust"));
1048 aAttribs[i].Handle = -1;
1049 aAttribs[i].Value = ::css::uno::makeAny( (sal_Int16)m_rEngine.GetTextAlign() );
1050 aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE;
1051 i++;
1052 }
1053 ::osl::MutexGuard aInternalGuard(GetMutex());
1054 ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber());
1055 // XXX numeric overflow
1056 // nIndex can be equal to Len();
1057 //if (nIndex < 0 || nIndex >= m_rEngine.GetText(nNumber).Len())
1058 if (nIndex < 0 || nIndex > m_rEngine.GetText(nNumber).Len())
1059 throw ::css::lang::IndexOutOfBoundsException(
1060 ::rtl::OUString(
1061 RTL_CONSTASCII_USTRINGPARAM(
1062 "textwindowaccessibility.cxx:"
1063 " Document::retrieveCharacterAttributes")),
1064 static_cast< ::css::uno::XWeak * >(this));
1065
1066 // retrieve default attributes
1067 tPropValMap aCharAttrSeq;
1068 retrieveDefaultAttributesImpl( pParagraph, aRequestedAttributes, aCharAttrSeq );
1069
1070 // retrieve run attributes
1071 tPropValMap aRunAttrSeq;
1072 retrieveRunAttributesImpl( pParagraph, nIndex, aRequestedAttributes, aRunAttrSeq );
1073
1074 // merge default and run attributes
1075 for ( tPropValMap::const_iterator aRunIter = aRunAttrSeq.begin();
1076 aRunIter != aRunAttrSeq.end();
1077 ++aRunIter )
1078 {
1079 aCharAttrSeq[ aRunIter->first ] = aRunIter->second;
1080 }
1081
1082 ::css::beans::PropertyValue* pValues = aAttribs.getArray();
1083 for (i = 0; i < AttributeCount; i++,pValues++)
1084 {
1085 aCharAttrSeq[ pValues->Name ] = *pValues;
1086 }
1087
1088 ::css::uno::Sequence< ::css::beans::PropertyValue > aRes = convertHashMapToSequence( aCharAttrSeq );
1089
1090 // sort the attributes
1091 sal_Int32 nLength = aRes.getLength();
1092 const ::css::beans::PropertyValue* pPairs = aRes.getConstArray();
1093 sal_Int32* pIndices = new sal_Int32[nLength];
1094 for( i = 0; i < nLength; i++ )
1095 pIndices[i] = i;
1096 std::sort( &pIndices[0], &pIndices[nLength], IndexCompare(pPairs) );
1097 // create sorted sequences according to index array
1098 ::css::uno::Sequence< ::css::beans::PropertyValue > aNewValues( nLength );
1099 ::css::beans::PropertyValue* pNewValues = aNewValues.getArray();
1100 for( i = 0; i < nLength; i++ )
1101 {
1102 pNewValues[i] = pPairs[pIndices[i]];
1103 }
1104 delete[] pIndices;
1105
1106 return aNewValues;
1107 }
1108
retrieveDefaultAttributesImpl(ParagraphImpl const * pParagraph,const::css::uno::Sequence<::rtl::OUString> & RequestedAttributes,tPropValMap & rDefAttrSeq)1109 void Document::retrieveDefaultAttributesImpl(
1110 ParagraphImpl const * pParagraph,
1111 const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes,
1112 tPropValMap& rDefAttrSeq)
1113 {
1114 // default attributes are not supported by text engine
1115 (void) pParagraph;
1116 (void) RequestedAttributes;
1117 (void) rDefAttrSeq;
1118 }
1119
1120 ::css::uno::Sequence< ::css::beans::PropertyValue >
retrieveDefaultAttributes(ParagraphImpl const * pParagraph,const::css::uno::Sequence<::rtl::OUString> & RequestedAttributes)1121 Document::retrieveDefaultAttributes(
1122 ParagraphImpl const * pParagraph,
1123 const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes)
1124 {
1125 ::osl::Guard< ::comphelper::IMutex > aExternalGuard( getExternalLock() );
1126 ::osl::MutexGuard aInternalGuard( GetMutex() );
1127
1128 tPropValMap aDefAttrSeq;
1129 retrieveDefaultAttributesImpl( pParagraph, RequestedAttributes, aDefAttrSeq );
1130 return convertHashMapToSequence( aDefAttrSeq );
1131 }
1132
1133 // static
1134 ::css::uno::Sequence< ::css::beans::PropertyValue >
convertHashMapToSequence(tPropValMap & rAttrSeq)1135 Document::convertHashMapToSequence(tPropValMap& rAttrSeq)
1136 {
1137 ::css::uno::Sequence< ::css::beans::PropertyValue > aValues( rAttrSeq.size() );
1138 ::css::beans::PropertyValue* pValues = aValues.getArray();
1139 ::sal_Int32 i = 0;
1140 for ( tPropValMap::const_iterator aIter = rAttrSeq.begin();
1141 aIter != rAttrSeq.end();
1142 ++aIter )
1143 {
1144 pValues[i] = aIter->second;
1145 ++i;
1146 }
1147 return aValues;
1148 }
1149
retrieveRunAttributesImpl(ParagraphImpl const * pParagraph,::sal_Int32 Index,const::css::uno::Sequence<::rtl::OUString> & RequestedAttributes,tPropValMap & rRunAttrSeq)1150 void Document::retrieveRunAttributesImpl(
1151 ParagraphImpl const * pParagraph, ::sal_Int32 Index,
1152 const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes,
1153 tPropValMap& rRunAttrSeq)
1154 {
1155 ::sal_uLong nNumber = static_cast< ::sal_uLong >( pParagraph->getNumber() );
1156 ::TextPaM aPaM( nNumber, static_cast< ::sal_uInt16 >( Index ) );
1157 // XXX numeric overflow
1158 // FIXME TEXTATTR_HYPERLINK ignored:
1159 ::TextAttribFontColor const * pColor
1160 = static_cast< ::TextAttribFontColor const * >(
1161 m_rEngine.FindAttrib( aPaM, TEXTATTR_FONTCOLOR ) );
1162 ::TextAttribFontWeight const * pWeight
1163 = static_cast< ::TextAttribFontWeight const * >(
1164 m_rEngine.FindAttrib( aPaM, TEXTATTR_FONTWEIGHT ) );
1165 tPropValMap aRunAttrSeq;
1166 if ( pColor )
1167 {
1168 ::css::beans::PropertyValue aPropVal;
1169 aPropVal.Name =
1170 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CharColor" ) );
1171 aPropVal.Handle = -1;
1172 aPropVal.Value = mapFontColor( pColor->GetColor() );
1173 aPropVal.State = ::css::beans::PropertyState_DIRECT_VALUE;
1174 aRunAttrSeq[ aPropVal.Name ] = aPropVal;
1175 }
1176 if ( pWeight )
1177 {
1178 ::css::beans::PropertyValue aPropVal;
1179 aPropVal.Name =
1180 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CharWeight" ) );
1181 aPropVal.Handle = -1;
1182 aPropVal.Value = mapFontWeight( pWeight->getFontWeight() );
1183 aPropVal.State = ::css::beans::PropertyState_DIRECT_VALUE;
1184 aRunAttrSeq[ aPropVal.Name ] = aPropVal;
1185 }
1186 if ( RequestedAttributes.getLength() == 0 )
1187 {
1188 rRunAttrSeq = aRunAttrSeq;
1189 }
1190 else
1191 {
1192 const ::rtl::OUString* pReqAttrs = RequestedAttributes.getConstArray();
1193 const ::sal_Int32 nLength = RequestedAttributes.getLength();
1194 for ( ::sal_Int32 i = 0; i < nLength; ++i )
1195 {
1196 tPropValMap::iterator aIter = aRunAttrSeq.find( pReqAttrs[i] );
1197 if ( aIter != aRunAttrSeq.end() )
1198 {
1199 rRunAttrSeq[ (*aIter).first ] = (*aIter).second;
1200 }
1201 }
1202 }
1203 }
1204
1205 ::css::uno::Sequence< ::css::beans::PropertyValue >
retrieveRunAttributes(ParagraphImpl const * pParagraph,::sal_Int32 Index,const::css::uno::Sequence<::rtl::OUString> & RequestedAttributes)1206 Document::retrieveRunAttributes(
1207 ParagraphImpl const * pParagraph, ::sal_Int32 Index,
1208 const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes)
1209 {
1210 ::osl::Guard< ::comphelper::IMutex > aExternalGuard( getExternalLock() );
1211 ::osl::MutexGuard aInternalGuard( GetMutex() );
1212 ::sal_uLong nNumber = static_cast< ::sal_uLong >( pParagraph->getNumber() );
1213 // XXX numeric overflow
1214 if ( Index < 0 || Index >= m_rEngine.GetText(nNumber).Len() )
1215 throw ::css::lang::IndexOutOfBoundsException(
1216 ::rtl::OUString(
1217 RTL_CONSTASCII_USTRINGPARAM(
1218 "textwindowaccessibility.cxx:"
1219 " Document::retrieveRunAttributes") ),
1220 static_cast< ::css::uno::XWeak * >( this ) );
1221
1222 tPropValMap aRunAttrSeq;
1223 retrieveRunAttributesImpl( pParagraph, Index, RequestedAttributes, aRunAttrSeq );
1224 return convertHashMapToSequence( aRunAttrSeq );
1225 }
1226
changeParagraphText(ParagraphImpl * pParagraph,::rtl::OUString const & rText)1227 void Document::changeParagraphText(ParagraphImpl * pParagraph,
1228 ::rtl::OUString const & rText)
1229 {
1230 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1231 {
1232 ::osl::MutexGuard aInternalGuard(GetMutex());
1233 ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber());
1234 // XXX numeric overflow
1235 changeParagraphText(nNumber, 0, m_rEngine.GetTextLen(nNumber), false,
1236 false, rText);
1237 }
1238 }
1239
changeParagraphText(ParagraphImpl * pParagraph,::sal_Int32 nBegin,::sal_Int32 nEnd,bool bCut,bool bPaste,::rtl::OUString const & rText)1240 void Document::changeParagraphText(ParagraphImpl * pParagraph,
1241 ::sal_Int32 nBegin, ::sal_Int32 nEnd,
1242 bool bCut, bool bPaste,
1243 ::rtl::OUString const & rText)
1244 {
1245 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1246 {
1247 ::osl::MutexGuard aInternalGuard(GetMutex());
1248 ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber());
1249 // XXX numeric overflow
1250 if (nBegin < 0 || nBegin > nEnd
1251 || nEnd > m_rEngine.GetText(nNumber).Len())
1252 throw ::css::lang::IndexOutOfBoundsException(
1253 ::rtl::OUString(
1254 RTL_CONSTASCII_USTRINGPARAM(
1255 "textwindowaccessibility.cxx:"
1256 " Document::changeParagraphText")),
1257 static_cast< ::css::uno::XWeak * >(this));
1258 changeParagraphText(nNumber, static_cast< ::sal_uInt16 >(nBegin),
1259 static_cast< ::sal_uInt16 >(nEnd), bCut, bPaste, rText);
1260 // XXX numeric overflow (2x)
1261 }
1262 }
1263
copyParagraphText(ParagraphImpl const * pParagraph,::sal_Int32 nBegin,::sal_Int32 nEnd)1264 void Document::copyParagraphText(ParagraphImpl const * pParagraph,
1265 ::sal_Int32 nBegin, ::sal_Int32 nEnd)
1266 {
1267 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1268 {
1269 ::osl::MutexGuard aInternalGuard(GetMutex());
1270 ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber());
1271 // XXX numeric overflow
1272 if (nBegin < 0 || nBegin > nEnd
1273 || nEnd > m_rEngine.GetText(nNumber).Len())
1274 throw ::css::lang::IndexOutOfBoundsException(
1275 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
1276 "textwindowaccessibility.cxx:"
1277 " Document::copyParagraphText")),
1278 static_cast< ::css::uno::XWeak * >(this));
1279 m_rView.SetSelection(
1280 ::TextSelection(::TextPaM(nNumber, static_cast< ::sal_uInt16 >(nBegin)),
1281 ::TextPaM(nNumber, static_cast< ::sal_uInt16 >(nEnd))));
1282 // XXX numeric overflow (2x)
1283 m_rView.Copy();
1284 }
1285 }
1286
changeParagraphAttributes(ParagraphImpl * pParagraph,::sal_Int32 nBegin,::sal_Int32 nEnd,::css::uno::Sequence<::css::beans::PropertyValue> const & rAttributeSet)1287 void Document::changeParagraphAttributes(
1288 ParagraphImpl * pParagraph, ::sal_Int32 nBegin, ::sal_Int32 nEnd,
1289 ::css::uno::Sequence< ::css::beans::PropertyValue > const & rAttributeSet)
1290 {
1291 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1292 {
1293 ::osl::MutexGuard aInternalGuard(GetMutex());
1294 ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber());
1295 // XXX numeric overflow
1296 if (nBegin < 0 || nBegin > nEnd
1297 || nEnd > m_rEngine.GetText(nNumber).Len())
1298 throw ::css::lang::IndexOutOfBoundsException(
1299 ::rtl::OUString(
1300 RTL_CONSTASCII_USTRINGPARAM(
1301 "textwindowaccessibility.cxx:"
1302 " Document::changeParagraphAttributes")),
1303 static_cast< ::css::uno::XWeak * >(this));
1304
1305 // FIXME The new attributes are added to any attributes already set,
1306 // they do not replace the old attributes as required by
1307 // XAccessibleEditableText.setAttributes:
1308 for (::sal_Int32 i = 0; i < rAttributeSet.getLength(); ++i)
1309 if (rAttributeSet[i].Name.equalsAsciiL(
1310 RTL_CONSTASCII_STRINGPARAM("CharColor")))
1311 m_rEngine.SetAttrib(::TextAttribFontColor(
1312 mapFontColor(rAttributeSet[i].Value)),
1313 nNumber, static_cast< ::sal_uInt16 >(nBegin),
1314 static_cast< ::sal_uInt16 >(nEnd));
1315 // XXX numeric overflow (2x)
1316 else if (rAttributeSet[i].Name.equalsAsciiL(
1317 RTL_CONSTASCII_STRINGPARAM("CharWeight")))
1318 m_rEngine.SetAttrib(::TextAttribFontWeight(
1319 mapFontWeight(rAttributeSet[i].Value)),
1320 nNumber, static_cast< ::sal_uInt16 >(nBegin),
1321 static_cast< ::sal_uInt16 >(nEnd));
1322 // XXX numeric overflow (2x)
1323 }
1324 }
1325
changeParagraphSelection(ParagraphImpl * pParagraph,::sal_Int32 nBegin,::sal_Int32 nEnd)1326 void Document::changeParagraphSelection(ParagraphImpl * pParagraph,
1327 ::sal_Int32 nBegin, ::sal_Int32 nEnd)
1328 {
1329 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1330 {
1331 ::osl::MutexGuard aInternalGuard(GetMutex());
1332 ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber());
1333 // XXX numeric overflow
1334 if (nBegin < 0 || nBegin > nEnd
1335 || nEnd > m_rEngine.GetText(nNumber).Len())
1336 throw ::css::lang::IndexOutOfBoundsException(
1337 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
1338 "textwindowaccessibility.cxx:"
1339 " Document::changeParagraphSelection")),
1340 static_cast< ::css::uno::XWeak * >(this));
1341 m_rView.SetSelection(
1342 ::TextSelection(::TextPaM(nNumber, static_cast< ::sal_uInt16 >(nBegin)),
1343 ::TextPaM(nNumber, static_cast< ::sal_uInt16 >(nEnd))));
1344 // XXX numeric overflow (2x)
1345 }
1346 }
1347
1348 ::css::i18n::Boundary
retrieveParagraphLineBoundary(ParagraphImpl const * pParagraph,::sal_Int32 nIndex,::sal_Int32 * pLineNo)1349 Document::retrieveParagraphLineBoundary( ParagraphImpl const * pParagraph,
1350 ::sal_Int32 nIndex, ::sal_Int32 *pLineNo )
1351 {
1352 ::css::i18n::Boundary aBoundary;
1353 aBoundary.startPos = nIndex;
1354 aBoundary.endPos = nIndex;
1355
1356 ::osl::Guard< ::comphelper::IMutex > aExternalGuard( getExternalLock() );
1357 {
1358 ::osl::MutexGuard aInternalGuard( GetMutex() );
1359 ::sal_uLong nNumber = static_cast< ::sal_uLong >( pParagraph->getNumber() );
1360 if ( nIndex < 0 || nIndex > m_rEngine.GetText( nNumber ).Len() )
1361 throw ::css::lang::IndexOutOfBoundsException(
1362 ::rtl::OUString(
1363 RTL_CONSTASCII_USTRINGPARAM(
1364 "textwindowaccessibility.cxx:"
1365 " Document::retrieveParagraphLineBoundary" ) ),
1366 static_cast< ::css::uno::XWeak * >( this ) );
1367 ::sal_Int32 nLineStart = 0;
1368 ::sal_Int32 nLineEnd = 0;
1369 ::sal_uInt16 nLineCount = m_rEngine.GetLineCount( nNumber );
1370 for ( ::sal_uInt16 nLine = 0; nLine < nLineCount; ++nLine )
1371 {
1372 ::sal_Int32 nLineLength = static_cast< ::sal_Int32 >(
1373 m_rEngine.GetLineLen( nNumber, nLine ) );
1374 nLineStart = nLineEnd;
1375 nLineEnd += nLineLength;
1376 if ( nIndex >= nLineStart && ( ( nLine == nLineCount - 1 ) ? nIndex <= nLineEnd : nIndex < nLineEnd ) )
1377 {
1378 aBoundary.startPos = nLineStart;
1379 aBoundary.endPos = nLineEnd;
1380 if( pLineNo )
1381 pLineNo[0] = nLine;
1382 break;
1383 }
1384 }
1385 }
1386
1387 return aBoundary;
1388 }
1389
1390 ::css::i18n::Boundary
retrieveParagraphBoundaryOfLine(ParagraphImpl const * pParagraph,::sal_Int32 nLineNo)1391 Document::retrieveParagraphBoundaryOfLine( ParagraphImpl const * pParagraph,
1392 ::sal_Int32 nLineNo )
1393 {
1394 ::css::i18n::Boundary aBoundary;
1395 aBoundary.startPos = 0;
1396 aBoundary.endPos = 0;
1397
1398 ::osl::Guard< ::comphelper::IMutex > aExternalGuard( getExternalLock() );
1399 {
1400 ::osl::MutexGuard aInternalGuard( GetMutex() );
1401 ::sal_uLong nNumber = static_cast< ::sal_uLong >( pParagraph->getNumber() );
1402 if ( nLineNo >= m_rEngine.GetLineCount( nNumber ) )
1403 throw ::css::lang::IndexOutOfBoundsException(
1404 ::rtl::OUString(
1405 RTL_CONSTASCII_USTRINGPARAM(
1406 "textwindowaccessibility.cxx:"
1407 " Document::retrieveParagraphBoundaryOfLine" ) ),
1408 static_cast< ::css::uno::XWeak * >( this ) );
1409 ::sal_Int32 nLineStart = 0;
1410 ::sal_Int32 nLineEnd = 0;
1411 for ( ::sal_uInt16 nLine = 0; nLine <= nLineNo; ++nLine )
1412 {
1413 ::sal_Int32 nLineLength = static_cast< ::sal_Int32 >(
1414 m_rEngine.GetLineLen( nNumber, nLine ) );
1415 nLineStart = nLineEnd;
1416 nLineEnd += nLineLength;
1417 }
1418
1419 aBoundary.startPos = nLineStart;
1420 aBoundary.endPos = nLineEnd;
1421 }
1422
1423 return aBoundary;
1424 }
1425
retrieveParagraphLineWithCursor(ParagraphImpl const * pParagraph)1426 sal_Int32 Document::retrieveParagraphLineWithCursor( ParagraphImpl const * pParagraph )
1427 {
1428 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1429 ::osl::MutexGuard aInternalGuard(GetMutex());
1430 ::TextSelection const & rSelection = m_rView.GetSelection();
1431 Paragraphs::size_type nNumber = pParagraph->getNumber();
1432 TextPaM aEndPaM( rSelection.GetEnd() );
1433
1434 return aEndPaM.GetPara() == nNumber
1435 ? m_rView.GetLineNumberOfCursorInSelection() : -1;
1436 }
1437
1438
1439 ::css::uno::Reference< ::css::accessibility::XAccessibleRelationSet >
retrieveParagraphRelationSet(ParagraphImpl const * pParagraph)1440 Document::retrieveParagraphRelationSet( ParagraphImpl const * pParagraph )
1441 {
1442 ::osl::MutexGuard aInternalGuard( GetMutex() );
1443
1444 ::utl::AccessibleRelationSetHelper* pRelationSetHelper = new ::utl::AccessibleRelationSetHelper();
1445 ::css::uno::Reference< ::css::accessibility::XAccessibleRelationSet > xSet = pRelationSetHelper;
1446
1447 Paragraphs::iterator aPara( m_xParagraphs->begin() + pParagraph->getNumber() );
1448
1449 if ( aPara > m_aVisibleBegin && aPara < m_aVisibleEnd )
1450 {
1451 ::css::uno::Sequence< ::css::uno::Reference< ::css::uno::XInterface > > aSequence(1);
1452 aSequence[0] = getAccessibleChild( aPara - 1 );
1453 ::css::accessibility::AccessibleRelation aRelation( ::css::accessibility::AccessibleRelationType::CONTENT_FLOWS_FROM, aSequence );
1454 pRelationSetHelper->AddRelation( aRelation );
1455 }
1456
1457 if ( aPara >= m_aVisibleBegin && aPara < m_aVisibleEnd -1 )
1458 {
1459 ::css::uno::Sequence< ::css::uno::Reference< ::css::uno::XInterface > > aSequence(1);
1460 aSequence[0] = getAccessibleChild( aPara + 1 );
1461 ::css::accessibility::AccessibleRelation aRelation( ::css::accessibility::AccessibleRelationType::CONTENT_FLOWS_TO, aSequence );
1462 pRelationSetHelper->AddRelation( aRelation );
1463 }
1464
1465 return xSet;
1466 }
1467
ProcessWindowEvent(const VclWindowEvent & rVclWindowEvent)1468 void Document::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent )
1469 {
1470 VCLXAccessibleComponent::ProcessWindowEvent( rVclWindowEvent );
1471 }
1472
1473 // virtual
getAccessibleChildCount()1474 ::sal_Int32 SAL_CALL Document::getAccessibleChildCount()
1475 {
1476 ::comphelper::OExternalLockGuard aGuard(this);
1477 init();
1478 return m_aVisibleEnd - m_aVisibleBegin;
1479 }
1480
1481 // virtual
1482 ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL
getAccessibleChild(::sal_Int32 i)1483 Document::getAccessibleChild(::sal_Int32 i)
1484 {
1485 ::comphelper::OExternalLockGuard aGuard(this);
1486 init();
1487 if (i < 0 || i >= m_aVisibleEnd - m_aVisibleBegin)
1488 throw ::css::lang::IndexOutOfBoundsException(
1489 ::rtl::OUString(
1490 RTL_CONSTASCII_USTRINGPARAM(
1491 "textwindowaccessibility.cxx:"
1492 " Document::getAccessibleChild")),
1493 static_cast< ::css::uno::XWeak * >(this));
1494 return getAccessibleChild(m_aVisibleBegin
1495 + static_cast< Paragraphs::size_type >(i));
1496 }
1497
1498 // virtual
getAccessibleRole()1499 ::sal_Int16 SAL_CALL Document::getAccessibleRole()
1500 {
1501 return ::css::accessibility::AccessibleRole::TEXT_FRAME;
1502 }
1503
1504 // virtual
1505 ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL
getAccessibleAtPoint(::css::awt::Point const & rPoint)1506 Document::getAccessibleAtPoint(::css::awt::Point const & rPoint)
1507 {
1508 ::comphelper::OExternalLockGuard aGuard(this);
1509 init();
1510 if (rPoint.X >= 0
1511 && rPoint.X < m_rView.GetWindow()->GetOutputSizePixel().Width()
1512 && rPoint.Y >= 0 && rPoint.Y < m_nViewHeight)
1513 {
1514 ::sal_Int32 nOffset = m_nViewOffset + rPoint.Y; // XXX numeric overflow
1515 ::sal_Int32 nPos = m_nViewOffset - m_nVisibleBeginOffset;
1516 for (Paragraphs::iterator aIt(m_aVisibleBegin); aIt != m_aVisibleEnd;
1517 ++aIt)
1518 {
1519 nPos += aIt->getHeight(); // XXX numeric overflow
1520 if (nOffset < nPos)
1521 return getAccessibleChild(aIt);
1522 }
1523 }
1524 return 0;
1525 }
FillAccessibleStateSet(utl::AccessibleStateSetHelper & rStateSet)1526 void Document::FillAccessibleStateSet( utl::AccessibleStateSetHelper& rStateSet )
1527 {
1528 VCLXAccessibleComponent::FillAccessibleStateSet( rStateSet );
1529 if (!m_rView.IsReadOnly())
1530 rStateSet.AddState( ::css::accessibility::AccessibleStateType::EDITABLE );
1531 }
1532
FillAccessibleRelationSet(utl::AccessibleRelationSetHelper & rRelationSet)1533 void Document::FillAccessibleRelationSet( utl::AccessibleRelationSetHelper& rRelationSet )
1534 {
1535 if( getAccessibleParent()->getAccessibleContext()->getAccessibleRole() == ::css::accessibility::AccessibleRole::SCROLL_PANE )
1536 {
1537 ::css::uno::Sequence< ::css::uno::Reference< ::css::uno::XInterface > > aSequence(1);
1538 aSequence[0] = getAccessibleParent();
1539 rRelationSet.AddRelation( ::css::accessibility::AccessibleRelation( ::css::accessibility::AccessibleRelationType::MEMBER_OF, aSequence ) );
1540 }
1541 else
1542 {
1543 VCLXAccessibleComponent::FillAccessibleRelationSet(rRelationSet);
1544 }
1545 }
1546 // virtual
disposing()1547 void SAL_CALL Document::disposing()
1548 {
1549 m_aEngineListener.endListening();
1550 m_aViewListener.endListening();
1551 if (m_xParagraphs.get() != 0)
1552 disposeParagraphs();
1553 VCLXAccessibleComponent::disposing();
1554 }
1555
1556 // virtual
Notify(::SfxBroadcaster &,::SfxHint const & rHint)1557 void Document::Notify(::SfxBroadcaster &, ::SfxHint const & rHint)
1558 {
1559 if (rHint.ISA(::TextHint))
1560 {
1561 ::TextHint const & rTextHint
1562 = static_cast< ::TextHint const & >(rHint);
1563 switch (rTextHint.GetId())
1564 {
1565 case TEXT_HINT_PARAINSERTED:
1566 case TEXT_HINT_PARAREMOVED:
1567 // TEXT_HINT_PARAINSERTED and TEXT_HINT_PARAREMOVED are sent at
1568 // "unsafe" times (when the text engine has not yet re-formatted its
1569 // content), so that for example calling ::TextEngine::GetTextHeight
1570 // from within the code that handles TEXT_HINT_PARAINSERTED causes
1571 // trouble within the text engine. Therefore, these hints are just
1572 // buffered until a following ::TextEngine::FormatDoc causes a
1573 // TEXT_HINT_TEXTFORMATTED to come in:
1574 case TEXT_HINT_FORMATPARA:
1575 // ::TextEngine::FormatDoc sends a sequence of
1576 // TEXT_HINT_FORMATPARAs, followed by an optional
1577 // TEXT_HINT_TEXTHEIGHTCHANGED, followed in all cases by one
1578 // TEXT_HINT_TEXTFORMATTED. Only the TEXT_HINT_FORMATPARAs contain
1579 // the numbers of the affected paragraphs, but they are sent
1580 // before the changes are applied. Therefore, TEXT_HINT_FORMATPARAs
1581 // are just buffered until another hint comes in:
1582 {
1583 ::osl::MutexGuard aInternalGuard(GetMutex());
1584 if (!isAlive())
1585 break;
1586
1587 m_aParagraphNotifications.push(rTextHint);
1588 break;
1589 }
1590 case TEXT_HINT_TEXTFORMATTED:
1591 case TEXT_HINT_TEXTHEIGHTCHANGED:
1592 case TEXT_HINT_MODIFIED:
1593 {
1594 ::osl::MutexGuard aInternalGuard(GetMutex());
1595 if (!isAlive())
1596 break;
1597 handleParagraphNotifications();
1598 break;
1599 }
1600 case TEXT_HINT_VIEWSCROLLED:
1601 {
1602 ::osl::MutexGuard aInternalGuard(GetMutex());
1603 if (!isAlive())
1604 break;
1605 handleParagraphNotifications();
1606
1607 ::sal_Int32 nOffset = static_cast< ::sal_Int32 >(
1608 m_rView.GetStartDocPos().Y());
1609 // XXX numeric overflow
1610 if (nOffset != m_nViewOffset)
1611 {
1612 m_nViewOffset = nOffset;
1613
1614 Paragraphs::iterator aOldVisibleBegin(
1615 m_aVisibleBegin);
1616 Paragraphs::iterator aOldVisibleEnd(m_aVisibleEnd);
1617
1618 determineVisibleRange();
1619
1620 notifyVisibleRangeChanges(aOldVisibleBegin,
1621 aOldVisibleEnd,
1622 m_xParagraphs->end());
1623 }
1624 break;
1625 }
1626 case TEXT_HINT_VIEWSELECTIONCHANGED:
1627 {
1628 ::osl::MutexGuard aInternalGuard(GetMutex());
1629 if (!isAlive())
1630 break;
1631
1632 if (m_aParagraphNotifications.empty())
1633 {
1634 handleSelectionChangeNotification();
1635 }
1636 else
1637 {
1638 // TEXT_HINT_VIEWSELECTIONCHANGED is sometimes sent at
1639 // "unsafe" times (when the text engine has not yet re-
1640 // formatted its content), so that for example calling
1641 // ::TextEngine::GetTextHeight from within the code that
1642 // handles a previous TEXT_HINT_PARAINSERTED causes
1643 // trouble within the text engine. Therefore, these
1644 // hints are just buffered (along with
1645 // TEXT_HINT_PARAINSERTED/REMOVED/FORMATPARA) until a
1646 // following ::TextEngine::FormatDoc causes a
1647 // TEXT_HINT_TEXTFORMATTED to come in:
1648 m_bSelectionChangedNotification = true;
1649 }
1650 break;
1651 }
1652 }
1653 }
1654 }
1655
IMPL_LINK(Document,WindowEventHandler,::VclSimpleEvent *,pEvent)1656 IMPL_LINK(Document, WindowEventHandler, ::VclSimpleEvent *, pEvent)
1657 {
1658 switch (pEvent->GetId())
1659 {
1660 case VCLEVENT_WINDOW_RESIZE:
1661 {
1662 ::osl::MutexGuard aInternalGuard(GetMutex());
1663 if (!isAlive())
1664 break;
1665
1666 ::sal_Int32 nHeight = static_cast< ::sal_Int32 >(
1667 m_rView.GetWindow()->GetOutputSizePixel().Height());
1668 // XXX numeric overflow
1669 if (nHeight != m_nViewHeight)
1670 {
1671 m_nViewHeight = nHeight;
1672
1673 Paragraphs::iterator aOldVisibleBegin(m_aVisibleBegin);
1674 Paragraphs::iterator aOldVisibleEnd(m_aVisibleEnd);
1675
1676 determineVisibleRange();
1677
1678 notifyVisibleRangeChanges(aOldVisibleBegin, aOldVisibleEnd,
1679 m_xParagraphs->end());
1680 }
1681 break;
1682 }
1683 case VCLEVENT_WINDOW_GETFOCUS:
1684 {
1685 ::osl::MutexGuard aInternalGuard(GetMutex());
1686 if (!isAlive())
1687 break;
1688 //to enable the PARAGRAPH to get focus for multiline edit
1689 ::sal_Int32 count = getAccessibleChildCount();
1690 ::sal_Bool bEmpty = m_aFocused == m_aVisibleEnd && count == 1;
1691 if ((m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd) || bEmpty)
1692 {
1693 Paragraphs::iterator m_aTemp = bEmpty ? m_aVisibleBegin : m_aFocused;
1694 ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(m_aTemp));
1695 if (xParagraph.is())
1696 {
1697 xParagraph->notifyEvent(
1698 ::css::accessibility::AccessibleEventId::
1699 STATE_CHANGED,
1700 ::css::uno::Any(),
1701 ::css::uno::makeAny(
1702 ::css::accessibility::AccessibleStateType::
1703 FOCUSED));
1704 }
1705 }
1706 /*
1707 ::rtl::Reference< ParagraphImpl > xParagraph(
1708 getParagraph(m_aFocused));
1709 if (xParagraph.is())
1710 xParagraph->notifyEvent(
1711 ::css::accessibility::AccessibleEventId::
1712 STATE_CHANGED,
1713 ::css::uno::Any(),
1714 ::css::uno::makeAny(
1715 ::css::accessibility::AccessibleStateType::
1716 FOCUSED));
1717 */
1718 break;
1719 }
1720 case VCLEVENT_WINDOW_LOSEFOCUS:
1721 {
1722 ::osl::MutexGuard aInternalGuard(GetMutex());
1723 if (!isAlive())
1724 break;
1725 //to enable the PARAGRAPH to get focus for multiline edit
1726 ::sal_Int32 count = getAccessibleChildCount();
1727 ::sal_Bool bEmpty = m_aFocused == m_aVisibleEnd && count == 1;
1728 if ((m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd) || bEmpty)
1729 {
1730 Paragraphs::iterator m_aTemp = bEmpty ? m_aVisibleBegin : m_aFocused;
1731 ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(m_aTemp));
1732 if (xParagraph.is())
1733 xParagraph->notifyEvent(
1734 ::css::accessibility::AccessibleEventId::
1735 STATE_CHANGED,
1736 ::css::uno::makeAny(
1737 ::css::accessibility::AccessibleStateType::
1738 FOCUSED),
1739 ::css::uno::Any());
1740 }
1741
1742 /*
1743 if (m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd)
1744 {
1745 ::rtl::Reference< ParagraphImpl > xParagraph(
1746 getParagraph(m_aFocused));
1747 if (xParagraph.is())
1748 xParagraph->notifyEvent(
1749 ::css::accessibility::AccessibleEventId::
1750 STATE_CHANGED,
1751 ::css::uno::makeAny(
1752 ::css::accessibility::AccessibleStateType::
1753 FOCUSED),
1754 ::css::uno::Any());
1755 }
1756 */
1757 break;
1758 }
1759 }
1760 return 0;
1761 }
1762
init()1763 void Document::init()
1764 {
1765 if (m_xParagraphs.get() == 0)
1766 {
1767 ::sal_uLong nCount = m_rEngine.GetParagraphCount();
1768 ::std::auto_ptr< Paragraphs > p(new Paragraphs);
1769 p->reserve(static_cast< Paragraphs::size_type >(nCount));
1770 // numeric overflow is harmless here
1771 for (::sal_uLong i = 0; i < nCount; ++i)
1772 p->push_back(ParagraphInfo(static_cast< ::sal_Int32 >(
1773 m_rEngine.GetTextHeight(i))));
1774 // XXX numeric overflow
1775 m_nViewOffset = static_cast< ::sal_Int32 >(
1776 m_rView.GetStartDocPos().Y()); // XXX numeric overflow
1777 m_nViewHeight = static_cast< ::sal_Int32 >(
1778 m_rView.GetWindow()->GetOutputSizePixel().Height());
1779 // XXX numeric overflow
1780 m_xParagraphs = p;
1781 determineVisibleRange();
1782 m_nSelectionFirstPara = -1;
1783 m_nSelectionFirstPos = -1;
1784 m_nSelectionLastPara = -1;
1785 m_nSelectionLastPos = -1;
1786 m_aFocused = m_xParagraphs->end();
1787 m_bSelectionChangedNotification = false;
1788 m_aEngineListener.startListening(m_rEngine);
1789 m_aViewListener.startListening(*m_rView.GetWindow());
1790 }
1791 }
1792
1793 ::rtl::Reference< ParagraphImpl >
getParagraph(Paragraphs::iterator const & rIt)1794 Document::getParagraph(Paragraphs::iterator const & rIt)
1795 {
1796 return static_cast< ParagraphImpl * >(
1797 ::css::uno::Reference< ::css::accessibility::XAccessible >(
1798 rIt->getParagraph()).get());
1799 }
1800
1801 ::css::uno::Reference< ::css::accessibility::XAccessible >
getAccessibleChild(Paragraphs::iterator const & rIt)1802 Document::getAccessibleChild(Paragraphs::iterator const & rIt)
1803 {
1804 ::css::uno::Reference< ::css::accessibility::XAccessible > xParagraph(
1805 rIt->getParagraph());
1806 if (!xParagraph.is())
1807 {
1808 xParagraph = new Paragraph(this, rIt - m_xParagraphs->begin());
1809 rIt->setParagraph(xParagraph);
1810 }
1811 return xParagraph;
1812 }
1813
determineVisibleRange()1814 void Document::determineVisibleRange()
1815 {
1816 m_aVisibleBegin = m_xParagraphs->end();
1817 m_aVisibleEnd = m_aVisibleBegin;
1818 ::sal_Int32 nPos = 0;
1819 for (Paragraphs::iterator aIt = m_xParagraphs->begin();;)
1820 {
1821 if (aIt == m_xParagraphs->end())
1822 {
1823 m_nVisibleBeginOffset = 0;
1824 break;
1825 }
1826 ::sal_Int32 nOldPos = nPos;
1827 nPos += aIt->getHeight(); // XXX numeric overflow
1828 if (m_aVisibleBegin == m_xParagraphs->end() && nPos >= m_nViewOffset)
1829 {
1830 m_aVisibleBegin = aIt;
1831 m_nVisibleBeginOffset = m_nViewOffset - nOldPos;
1832 }
1833 ++aIt;
1834 if (m_aVisibleBegin != m_xParagraphs->end()
1835 && (aIt == m_xParagraphs->end()
1836 || nPos >= m_nViewOffset + m_nViewHeight))
1837 // XXX numeric overflow
1838 {
1839 m_aVisibleEnd = aIt;
1840 break;
1841 }
1842 }
1843 }
1844
notifyVisibleRangeChanges(Paragraphs::iterator const & rOldVisibleBegin,Paragraphs::iterator const & rOldVisibleEnd,Paragraphs::iterator const & rInserted)1845 void Document::notifyVisibleRangeChanges(
1846 Paragraphs::iterator const & rOldVisibleBegin,
1847 Paragraphs::iterator const & rOldVisibleEnd,
1848 Paragraphs::iterator const & rInserted)
1849 {
1850 // XXX Replace this code that determines which paragraphs have changed from
1851 // invisible to visible or vice versa with a better algorithm.
1852 {for (Paragraphs::iterator aIt(rOldVisibleBegin); aIt != rOldVisibleEnd;
1853 ++aIt)
1854 if (aIt != rInserted
1855 && (aIt < m_aVisibleBegin || aIt >= m_aVisibleEnd))
1856 NotifyAccessibleEvent(
1857 ::css::accessibility::AccessibleEventId::
1858 CHILD,
1859 ::css::uno::makeAny(getAccessibleChild(aIt)),
1860 ::css::uno::Any());
1861 }
1862 {for (Paragraphs::iterator aIt(m_aVisibleBegin); aIt != m_aVisibleEnd;
1863 ++aIt)
1864 if (aIt == rInserted
1865 || aIt < rOldVisibleBegin || aIt >= rOldVisibleEnd)
1866 NotifyAccessibleEvent(
1867 ::css::accessibility::AccessibleEventId::
1868 CHILD,
1869 ::css::uno::Any(),
1870 ::css::uno::makeAny(getAccessibleChild(aIt)));
1871 }
1872 }
1873
1874 void
changeParagraphText(::sal_uLong nNumber,::sal_uInt16 nBegin,::sal_uInt16 nEnd,bool bCut,bool bPaste,::rtl::OUString const & rText)1875 Document::changeParagraphText(::sal_uLong nNumber, ::sal_uInt16 nBegin, ::sal_uInt16 nEnd,
1876 bool bCut, bool bPaste,
1877 ::rtl::OUString const & rText)
1878 {
1879 m_rView.SetSelection(::TextSelection(::TextPaM(nNumber, nBegin),
1880 ::TextPaM(nNumber, nEnd)));
1881 if (bCut)
1882 m_rView.Cut();
1883 else if (nBegin != nEnd)
1884 m_rView.DeleteSelected();
1885 if (bPaste)
1886 m_rView.Paste();
1887 else if ( !rText.isEmpty() )
1888 m_rView.InsertText(rText);
1889 }
1890
handleParagraphNotifications()1891 void Document::handleParagraphNotifications()
1892 {
1893 while (!m_aParagraphNotifications.empty())
1894 {
1895 ::TextHint aHint(m_aParagraphNotifications.front());
1896 m_aParagraphNotifications.pop();
1897 switch (aHint.GetId())
1898 {
1899 case TEXT_HINT_PARAINSERTED:
1900 {
1901 ::sal_uLong n = aHint.GetValue();
1902 OSL_ENSURE(n <= m_xParagraphs->size(),
1903 "bad TEXT_HINT_PARAINSERTED event");
1904
1905 // Save the values of old iterators (the iterators themselves
1906 // will get invalidated), and adjust the old values so that they
1907 // reflect the insertion of the new paragraph:
1908 Paragraphs::size_type nOldVisibleBegin
1909 = m_aVisibleBegin - m_xParagraphs->begin();
1910 Paragraphs::size_type nOldVisibleEnd
1911 = m_aVisibleEnd - m_xParagraphs->begin();
1912 Paragraphs::size_type nOldFocused
1913 = m_aFocused - m_xParagraphs->begin();
1914 if (n <= nOldVisibleBegin)
1915 ++nOldVisibleBegin; // XXX numeric overflow
1916 if (n <= nOldVisibleEnd)
1917 ++nOldVisibleEnd; // XXX numeric overflow
1918 if (n <= nOldFocused)
1919 ++nOldFocused; // XXX numeric overflow
1920 if (sal::static_int_cast<sal_Int32>(n) <= m_nSelectionFirstPara)
1921 ++m_nSelectionFirstPara; // XXX numeric overflow
1922 if (sal::static_int_cast<sal_Int32>(n) <= m_nSelectionLastPara)
1923 ++m_nSelectionLastPara; // XXX numeric overflow
1924
1925 Paragraphs::iterator aIns(
1926 m_xParagraphs->insert(
1927 m_xParagraphs->begin() + n,
1928 ParagraphInfo(static_cast< ::sal_Int32 >(
1929 m_rEngine.GetTextHeight(n)))));
1930 // XXX numeric overflow (2x)
1931
1932 determineVisibleRange();
1933 m_aFocused = m_xParagraphs->begin() + nOldFocused;
1934
1935 for (Paragraphs::iterator aIt(aIns);;)
1936 {
1937 ++aIt;
1938 if (aIt == m_xParagraphs->end())
1939 break;
1940 ::rtl::Reference< ParagraphImpl > xParagraph(
1941 getParagraph(aIt));
1942 if (xParagraph.is())
1943 xParagraph->numberChanged(true);
1944 }
1945
1946 notifyVisibleRangeChanges(
1947 m_xParagraphs->begin() + nOldVisibleBegin,
1948 m_xParagraphs->begin() + nOldVisibleEnd, aIns);
1949 break;
1950 }
1951 case TEXT_HINT_PARAREMOVED:
1952 {
1953 ::sal_uLong n = aHint.GetValue();
1954 if (n == TEXT_PARA_ALL)
1955 {
1956 {for (Paragraphs::iterator aIt(m_aVisibleBegin);
1957 aIt != m_aVisibleEnd; ++aIt)
1958 NotifyAccessibleEvent(
1959 ::css::accessibility::AccessibleEventId::
1960 CHILD,
1961 ::css::uno::makeAny(getAccessibleChild(aIt)),
1962 ::css::uno::Any());
1963 }
1964 disposeParagraphs();
1965 m_xParagraphs->clear();
1966 determineVisibleRange();
1967 m_nSelectionFirstPara = -1;
1968 m_nSelectionFirstPos = -1;
1969 m_nSelectionLastPara = -1;
1970 m_nSelectionLastPos = -1;
1971 m_aFocused = m_xParagraphs->end();
1972 }
1973 else
1974 {
1975 OSL_ENSURE(n < m_xParagraphs->size(),
1976 "Bad TEXT_HINT_PARAREMOVED event");
1977
1978 Paragraphs::iterator aIt(m_xParagraphs->begin() + n);
1979 // numeric overflow cannot occur
1980
1981 // Save the values of old iterators (the iterators
1982 // themselves will get invalidated), and adjust the old
1983 // values so that they reflect the removal of the paragraph:
1984 Paragraphs::size_type nOldVisibleBegin
1985 = m_aVisibleBegin - m_xParagraphs->begin();
1986 Paragraphs::size_type nOldVisibleEnd
1987 = m_aVisibleEnd - m_xParagraphs->begin();
1988 bool bWasVisible
1989 = nOldVisibleBegin <= n && n < nOldVisibleEnd;
1990 Paragraphs::size_type nOldFocused
1991 = m_aFocused - m_xParagraphs->begin();
1992 bool bWasFocused = aIt == m_aFocused;
1993 if (n < nOldVisibleBegin)
1994 --nOldVisibleBegin;
1995 if (n < nOldVisibleEnd)
1996 --nOldVisibleEnd;
1997 if (n < nOldFocused)
1998 --nOldFocused;
1999 if (sal::static_int_cast<sal_Int32>(n) < m_nSelectionFirstPara)
2000 --m_nSelectionFirstPara;
2001 else if (sal::static_int_cast<sal_Int32>(n) == m_nSelectionFirstPara)
2002 {
2003 if (m_nSelectionFirstPara == m_nSelectionLastPara)
2004 {
2005 m_nSelectionFirstPara = -1;
2006 m_nSelectionFirstPos = -1;
2007 m_nSelectionLastPara = -1;
2008 m_nSelectionLastPos = -1;
2009 }
2010 else
2011 {
2012 ++m_nSelectionFirstPara;
2013 m_nSelectionFirstPos = 0;
2014 }
2015 }
2016 if (sal::static_int_cast<sal_Int32>(n) < m_nSelectionLastPara)
2017 --m_nSelectionLastPara;
2018 else if (sal::static_int_cast<sal_Int32>(n) == m_nSelectionLastPara)
2019 {
2020 OSL_ENSURE(m_nSelectionFirstPara < m_nSelectionLastPara,
2021 "logic error");
2022 --m_nSelectionLastPara;
2023 m_nSelectionLastPos = 0x7FFFFFFF;
2024 }
2025
2026 ::css::uno::Reference< ::css::accessibility::XAccessible >
2027 xStrong;
2028 if (bWasVisible)
2029 xStrong = getAccessibleChild(aIt);
2030 ::css::uno::WeakReference<
2031 ::css::accessibility::XAccessible > xWeak(
2032 aIt->getParagraph());
2033 aIt = m_xParagraphs->erase(aIt);
2034
2035 determineVisibleRange();
2036 m_aFocused = bWasFocused ? m_xParagraphs->end()
2037 : m_xParagraphs->begin() + nOldFocused;
2038
2039 for (; aIt != m_xParagraphs->end(); ++aIt)
2040 {
2041 ::rtl::Reference< ParagraphImpl > xParagraph(
2042 getParagraph(aIt));
2043 if (xParagraph.is())
2044 xParagraph->numberChanged(false);
2045 }
2046
2047 if (bWasVisible)
2048 NotifyAccessibleEvent(
2049 ::css::accessibility::AccessibleEventId::
2050 CHILD,
2051 ::css::uno::makeAny(getAccessibleChild(aIt)),
2052 ::css::uno::Any());
2053
2054 ::css::uno::Reference< ::css::lang::XComponent > xComponent(
2055 xWeak.get(), ::css::uno::UNO_QUERY);
2056 if (xComponent.is())
2057 xComponent->dispose();
2058
2059 notifyVisibleRangeChanges(
2060 m_xParagraphs->begin() + nOldVisibleBegin,
2061 m_xParagraphs->begin() + nOldVisibleEnd,
2062 m_xParagraphs->end());
2063 }
2064 break;
2065 }
2066 case TEXT_HINT_FORMATPARA:
2067 {
2068 ::sal_uLong n = aHint.GetValue();
2069 OSL_ENSURE(n < m_xParagraphs->size(),
2070 "Bad TEXT_HINT_FORMATPARA event");
2071
2072 (*m_xParagraphs)[static_cast< Paragraphs::size_type >(n)].
2073 changeHeight(static_cast< ::sal_Int32 >(
2074 m_rEngine.GetTextHeight(n)));
2075 // XXX numeric overflow
2076 Paragraphs::iterator aOldVisibleBegin(m_aVisibleBegin);
2077 Paragraphs::iterator aOldVisibleEnd(m_aVisibleEnd);
2078 determineVisibleRange();
2079 notifyVisibleRangeChanges(aOldVisibleBegin, aOldVisibleEnd,
2080 m_xParagraphs->end());
2081
2082 if (n < m_xParagraphs->size())
2083 {
2084 Paragraphs::iterator aIt(m_xParagraphs->begin() + n);
2085 ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(aIt));
2086 if (xParagraph.is())
2087 xParagraph->textChanged();
2088 }
2089 break;
2090 }
2091 default:
2092 OSL_ENSURE(false, "bad buffered hint");
2093 break;
2094 }
2095 }
2096 if (m_bSelectionChangedNotification)
2097 {
2098 m_bSelectionChangedNotification = false;
2099 handleSelectionChangeNotification();
2100 }
2101 }
2102
getSelectionType(::sal_Int32 nNewFirstPara,::sal_Int32 nNewFirstPos,::sal_Int32 nNewLastPara,::sal_Int32 nNewLastPos)2103 ::sal_Int32 Document::getSelectionType(::sal_Int32 nNewFirstPara, ::sal_Int32 nNewFirstPos, ::sal_Int32 nNewLastPara, ::sal_Int32 nNewLastPos)
2104 {
2105 if (m_nSelectionFirstPara == -1)
2106 return -1;
2107 ::sal_Int32 Osp = m_nSelectionFirstPara, Osl = m_nSelectionFirstPos, Oep = m_nSelectionLastPara, Oel = m_nSelectionLastPos;
2108 ::sal_Int32 Nsp = nNewFirstPara, Nsl = nNewFirstPos, Nep = nNewLastPara, Nel = nNewLastPos;
2109 TextPaM Ns(Nsp, sal_uInt16(Nsl));
2110 TextPaM Ne(Nep, sal_uInt16(Nel));
2111 TextPaM Os(Osp, sal_uInt16(Osl));
2112 TextPaM Oe(Oep, sal_uInt16(Oel));
2113
2114 if (Os == Oe && Ns == Ne)
2115 {
2116 //only caret moves.
2117 return 1;
2118 }
2119 else if (Os == Oe && Ns != Ne)
2120 {
2121 //old has no selection but new has selection
2122 return 2;
2123 }
2124 else if (Os != Oe && Ns == Ne)
2125 {
2126 //old has selection but new has no selection.
2127 return 3;
2128 }
2129 else if (Os != Oe && Ns != Ne && Osp == Nsp && Osl == Nsl)
2130 {
2131 //both old and new have selections.
2132 if (Oep == Nep )
2133 {
2134 //Send text_selection_change event on Nep
2135
2136 return 4;
2137 }
2138 else if (Oep < Nep)
2139 {
2140 //all the following examples like 1,2->1,3 means that old start select para is 1, old end select para is 2,
2141 // then press shift up, the new start select para is 1, new end select para is 3;
2142 //for example, 1, 2 -> 1, 3; 4,1 -> 4, 7; 4,1 -> 4, 2; 4,4->4,5
2143 if (Nep >= Nsp)
2144 {
2145 // 1, 2 -> 1, 3; 4, 1 -> 4, 7; 4,4->4,5;
2146 if (Oep < Osp)
2147 {
2148 // 4,1 -> 4,7;
2149 return 5;
2150 }
2151 else if (Oep >= Osp)
2152 {
2153 // 1, 2 -> 1, 3; 4,4->4,5;
2154 return 6;
2155 }
2156 }
2157 else
2158 {
2159 // 4,1 -> 4,2,
2160 if (Oep < Osp)
2161 {
2162 // 4,1 -> 4,2,
2163 return 7;
2164 }
2165 else if (Oep >= Osp)
2166 {
2167 // no such condition. Oep > Osp = Nsp > Nep
2168 }
2169 }
2170 }
2171 else if (Oep > Nep)
2172 {
2173 // 3,2 -> 3,1; 4,7 -> 4,1; 4, 7 -> 4,6; 4,4 -> 4,3
2174 if (Nep >= Nsp)
2175 {
2176 // 4,7 -> 4,6
2177 if (Oep <= Osp)
2178 {
2179 //no such condition, Oep<Osp=Nsp <= Nep
2180 }
2181 else if (Oep > Osp)
2182 {
2183 // 4,7 ->4,6
2184 return 8;
2185 }
2186 }
2187 else
2188 {
2189 // 3,2 -> 3,1, 4,7 -> 4,1; 4,4->4,3
2190 if (Oep <= Osp)
2191 {
2192 // 3,2 -> 3,1; 4,4->4,3
2193 return 9;
2194 }
2195 else if (Oep > Osp)
2196 {
2197 // 4,7 -> 4,1
2198 return 10;
2199 }
2200 }
2201 }
2202 }
2203 return -1;
2204 }
2205
2206
sendEvent(::sal_Int32 start,::sal_Int32 end,::sal_Int16 nEventId)2207 void Document::sendEvent(::sal_Int32 start, ::sal_Int32 end, ::sal_Int16 nEventId)
2208 {
2209 Paragraphs::iterator aEnd = ::std::min(m_xParagraphs->begin() + end + 1, m_aVisibleEnd);
2210 for (Paragraphs::iterator aIt = ::std::max(m_xParagraphs->begin() + start, m_aVisibleBegin);
2211 aIt < aEnd; ++aIt)
2212 {
2213 ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(aIt));
2214 if (xParagraph.is())
2215 xParagraph->notifyEvent(
2216 nEventId,
2217 ::css::uno::Any(), ::css::uno::Any());
2218 }
2219 }
2220
handleSelectionChangeNotification()2221 void Document::handleSelectionChangeNotification()
2222 {
2223 ::TextSelection const & rSelection = m_rView.GetSelection();
2224 OSL_ENSURE(rSelection.GetStart().GetPara() < m_xParagraphs->size()
2225 && rSelection.GetEnd().GetPara() < m_xParagraphs->size(),
2226 "bad TEXT_HINT_VIEWSELECTIONCHANGED event");
2227 ::sal_Int32 nNewFirstPara
2228 = static_cast< ::sal_Int32 >(rSelection.GetStart().GetPara());
2229 ::sal_Int32 nNewFirstPos
2230 = static_cast< ::sal_Int32 >(rSelection.GetStart().GetIndex());
2231 // XXX numeric overflow
2232 ::sal_Int32 nNewLastPara
2233 = static_cast< ::sal_Int32 >(rSelection.GetEnd().GetPara());
2234 ::sal_Int32 nNewLastPos
2235 = static_cast< ::sal_Int32 >(rSelection.GetEnd().GetIndex());
2236 // XXX numeric overflow
2237
2238 // Lose focus:
2239 Paragraphs::iterator aIt(m_xParagraphs->begin() + nNewLastPara);
2240 if (m_aFocused != m_xParagraphs->end() && m_aFocused != aIt
2241 && m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd)
2242 {
2243 ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(m_aFocused));
2244 if (xParagraph.is())
2245 xParagraph->notifyEvent(
2246 ::css::accessibility::AccessibleEventId::
2247 STATE_CHANGED,
2248 ::css::uno::makeAny(
2249 ::css::accessibility::AccessibleStateType::FOCUSED),
2250 ::css::uno::Any());
2251 }
2252
2253 // Gain focus and update cursor position:
2254 if (aIt >= m_aVisibleBegin && aIt < m_aVisibleEnd
2255 && (aIt != m_aFocused
2256 || nNewLastPara != m_nSelectionLastPara
2257 || nNewLastPos != m_nSelectionLastPos))
2258 {
2259 ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(aIt));
2260 if (xParagraph.is())
2261 {
2262 //disable the first event when user types in empty field.
2263 ::sal_Int32 count = getAccessibleChildCount();
2264 ::sal_Bool bEmpty = count > 1;
2265 //if (aIt != m_aFocused)
2266 if (aIt != m_aFocused && bEmpty)
2267 xParagraph->notifyEvent(
2268 ::css::accessibility::AccessibleEventId::
2269 STATE_CHANGED,
2270 ::css::uno::Any(),
2271 ::css::uno::makeAny(
2272 ::css::accessibility::AccessibleStateType::FOCUSED));
2273 if (nNewLastPara != m_nSelectionLastPara
2274 || nNewLastPos != m_nSelectionLastPos)
2275 xParagraph->notifyEvent(
2276 ::css::accessibility::AccessibleEventId::
2277 CARET_CHANGED,
2278 ::css::uno::makeAny< ::sal_Int32 >(
2279 nNewLastPara == m_nSelectionLastPara
2280 ? m_nSelectionLastPos : 0),
2281 ::css::uno::makeAny(nNewLastPos));
2282 }
2283 }
2284 m_aFocused = aIt;
2285
2286 ::sal_Int32 nMin;
2287 ::sal_Int32 nMax;
2288 ::sal_Int32 ret = getSelectionType(nNewFirstPara, nNewFirstPos, nNewLastPara, nNewLastPos);
2289 switch (ret)
2290 {
2291 case -1:
2292 {
2293 //no event
2294 }
2295 break;
2296 case 1:
2297 {
2298 //only caret moved, already handled in above
2299 }
2300 break;
2301 case 2:
2302 {
2303 //old has no selection but new has selection
2304 nMin = ::std::min(nNewFirstPara, nNewLastPara);
2305 nMax = ::std::max(nNewFirstPara, nNewLastPara);
2306 sendEvent(nMin, nMax, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2307 sendEvent(nMin, nMax, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2308 }
2309 break;
2310 case 3:
2311 {
2312 //old has selection but new has no selection.
2313 nMin = ::std::min(m_nSelectionFirstPara, m_nSelectionLastPara);
2314 nMax = ::std::max(m_nSelectionFirstPara, m_nSelectionLastPara);
2315 sendEvent(nMin, nMax, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2316 sendEvent(nMin, nMax, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2317 }
2318 break;
2319 case 4:
2320 {
2321 //Send text_selection_change event on Nep
2322 sendEvent(nNewLastPara, nNewLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2323 }
2324 break;
2325 case 5:
2326 {
2327 // 4, 1 -> 4, 7
2328 sendEvent(m_nSelectionLastPara, m_nSelectionFirstPara-1, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2329 sendEvent(nNewFirstPara+1, nNewLastPara, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2330
2331 sendEvent(m_nSelectionLastPara, nNewLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2332 }
2333 break;
2334 case 6:
2335 {
2336 // 1, 2 -> 1, 4; 4,4->4,5;
2337 sendEvent(m_nSelectionLastPara+1, nNewLastPara, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2338
2339 sendEvent(m_nSelectionLastPara, nNewLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2340 }
2341 break;
2342 case 7:
2343 {
2344 // 4,1 -> 4,3,
2345 sendEvent(m_nSelectionLastPara +1, nNewLastPara , ::css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2346
2347 sendEvent(m_nSelectionLastPara, nNewLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2348 }
2349 break;
2350 case 8:
2351 {
2352 // 4,7 ->4,5;
2353 sendEvent(nNewLastPara + 1, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2354
2355 sendEvent(nNewLastPara, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2356 }
2357 break;
2358 case 9:
2359 {
2360 // 3,2 -> 3,1; 4,4->4,3
2361 sendEvent(nNewLastPara, m_nSelectionLastPara - 1, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2362
2363 sendEvent(nNewLastPara, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2364 }
2365 break;
2366 case 10:
2367 {
2368 // 4,7 -> 4,1
2369 sendEvent(m_nSelectionFirstPara + 1, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2370 sendEvent(nNewLastPara, nNewFirstPara - 1, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2371
2372 sendEvent(nNewLastPara, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2373 }
2374 break;
2375 default:
2376 break;
2377 }
2378
2379 /*
2380 // Update both old and new selection. (Regardless of how the two selections
2381 // look like, there will always be two ranges to the left and right of the
2382 // overlap---the overlap and/or the range to the right of it possibly being
2383 // empty. Only for these two ranges notifications have to be sent.)
2384
2385 TextPaM aOldTextStart( static_cast< sal_uLong >( m_nSelectionFirstPara ), static_cast< sal_uInt16 >( m_nSelectionFirstPos ) );
2386 TextPaM aOldTextEnd( static_cast< sal_uLong >( m_nSelectionLastPara ), static_cast< sal_uInt16 >( m_nSelectionLastPos ) );
2387 TextPaM aNewTextStart( static_cast< sal_uLong >( nNewFirstPara ), static_cast< sal_uInt16 >( nNewFirstPos ) );
2388 TextPaM aNewTextEnd( static_cast< sal_uLong >( nNewLastPara ), static_cast< sal_uInt16 >( nNewLastPos ) );
2389
2390 // justify selections
2391 justifySelection( aOldTextStart, aOldTextEnd );
2392 justifySelection( aNewTextStart, aNewTextEnd );
2393
2394 sal_Int32 nFirst1;
2395 sal_Int32 nLast1;
2396 sal_Int32 nFirst2;
2397 sal_Int32 nLast2;
2398
2399 if ( m_nSelectionFirstPara == -1 )
2400 {
2401 // old selection not initialized yet => notify events only for new selection (if not empty)
2402 nFirst1 = aNewTextStart.GetPara();
2403 nLast1 = aNewTextEnd.GetPara() + ( aNewTextStart != aNewTextEnd ? 1 : 0 );
2404 nFirst2 = 0;
2405 nLast2 = 0;
2406 }
2407 else if ( aOldTextStart == aOldTextEnd && aNewTextStart == aNewTextEnd )
2408 {
2409 // old an new selection empty => no events
2410 nFirst1 = 0;
2411 nLast1 = 0;
2412 nFirst2 = 0;
2413 nLast2 = 0;
2414 }
2415 else if ( aOldTextStart != aOldTextEnd && aNewTextStart == aNewTextEnd )
2416 {
2417 // old selection not empty + new selection empty => notify events only for old selection
2418 nFirst1 = aOldTextStart.GetPara();
2419 nLast1 = aOldTextEnd.GetPara() + 1;
2420 nFirst2 = 0;
2421 nLast2 = 0;
2422 }
2423 else if ( aOldTextStart == aOldTextEnd && aNewTextStart != aNewTextEnd )
2424 {
2425 // old selection empty + new selection not empty => notify events only for new selection
2426 nFirst1 = aNewTextStart.GetPara();
2427 nLast1 = aNewTextEnd.GetPara() + 1;
2428 nFirst2 = 0;
2429 nLast2 = 0;
2430 }
2431 else
2432 {
2433 // old and new selection not empty => notify events for the two ranges left and right of the overlap
2434 ::std::vector< TextPaM > aTextPaMs(4);
2435 aTextPaMs[0] = aOldTextStart;
2436 aTextPaMs[1] = aOldTextEnd;
2437 aTextPaMs[2] = aNewTextStart;
2438 aTextPaMs[3] = aNewTextEnd;
2439 ::std::sort( aTextPaMs.begin(), aTextPaMs.end() );
2440
2441 nFirst1 = aTextPaMs[0].GetPara();
2442 nLast1 = aTextPaMs[1].GetPara() + ( aTextPaMs[0] != aTextPaMs[1] ? 1 : 0 );
2443
2444 nFirst2 = aTextPaMs[2].GetPara();
2445 nLast2 = aTextPaMs[3].GetPara() + ( aTextPaMs[2] != aTextPaMs[3] ? 1 : 0 );
2446
2447 // adjust overlapping ranges
2448 if ( nLast1 > nFirst2 )
2449 nLast1 = nFirst2;
2450 }
2451
2452 // notify selection changes
2453 notifySelectionChange( nFirst1, nLast1 );
2454 notifySelectionChange( nFirst2, nLast2 );
2455 */
2456 m_nSelectionFirstPara = nNewFirstPara;
2457 m_nSelectionFirstPos = nNewFirstPos;
2458 m_nSelectionLastPara = nNewLastPara;
2459 m_nSelectionLastPos = nNewLastPos;
2460 }
2461
notifySelectionChange(sal_Int32 nFirst,sal_Int32 nLast)2462 void Document::notifySelectionChange( sal_Int32 nFirst, sal_Int32 nLast )
2463 {
2464 if ( nFirst < nLast )
2465 {
2466 Paragraphs::iterator aEnd( ::std::min( m_xParagraphs->begin() + nLast, m_aVisibleEnd ) );
2467 for ( Paragraphs::iterator aIt = ::std::max( m_xParagraphs->begin() + nFirst, m_aVisibleBegin ); aIt < aEnd; ++aIt )
2468 {
2469 ::rtl::Reference< ParagraphImpl > xParagraph( getParagraph( aIt ) );
2470 if ( xParagraph.is() )
2471 {
2472 xParagraph->notifyEvent(
2473 ::css::accessibility::AccessibleEventId::SELECTION_CHANGED,
2474 ::css::uno::Any(), ::css::uno::Any() );
2475 xParagraph->notifyEvent(
2476 ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED,
2477 ::css::uno::Any(), ::css::uno::Any() );
2478 }
2479 }
2480 }
2481 }
2482
justifySelection(TextPaM & rTextStart,TextPaM & rTextEnd)2483 void Document::justifySelection( TextPaM& rTextStart, TextPaM& rTextEnd )
2484 {
2485 if ( rTextStart > rTextEnd )
2486 {
2487 TextPaM aTextPaM( rTextStart );
2488 rTextStart = rTextEnd;
2489 rTextEnd = aTextPaM;
2490 }
2491 }
2492
disposeParagraphs()2493 void Document::disposeParagraphs()
2494 {
2495 for (Paragraphs::iterator aIt(m_xParagraphs->begin());
2496 aIt != m_xParagraphs->end(); ++aIt)
2497 {
2498 ::css::uno::Reference< ::css::lang::XComponent > xComponent(
2499 aIt->getParagraph().get(), ::css::uno::UNO_QUERY);
2500 if (xComponent.is())
2501 xComponent->dispose();
2502 }
2503 }
2504
2505 // static
mapFontColor(::Color const & rColor)2506 ::css::uno::Any Document::mapFontColor(::Color const & rColor)
2507 {
2508 return ::css::uno::makeAny(
2509 static_cast< ::sal_Int32 >(COLORDATA_RGB(rColor.GetColor())));
2510 // FIXME keep transparency?
2511 }
2512
2513 // static
mapFontColor(::css::uno::Any const & rColor)2514 ::Color Document::mapFontColor(::css::uno::Any const & rColor)
2515 {
2516 ::sal_Int32 nColor = 0;
2517 rColor >>= nColor;
2518 return ::Color(static_cast< ::ColorData >(nColor));
2519 }
2520
2521 // static
mapFontWeight(::FontWeight nWeight)2522 ::css::uno::Any Document::mapFontWeight(::FontWeight nWeight)
2523 {
2524 // Map from ::FontWeight to ::css:awt::FontWeight, depends on order of
2525 // elements in ::FontWeight (vcl/vclenum.hxx):
2526 static float const aWeight[]
2527 = { ::css::awt::FontWeight::DONTKNOW, // WEIGHT_DONTKNOW
2528 ::css::awt::FontWeight::THIN, // WEIGHT_THIN
2529 ::css::awt::FontWeight::ULTRALIGHT, // WEIGHT_ULTRALIGHT
2530 ::css::awt::FontWeight::LIGHT, // WEIGHT_LIGHT
2531 ::css::awt::FontWeight::SEMILIGHT, // WEIGHT_SEMILIGHT
2532 ::css::awt::FontWeight::NORMAL, // WEIGHT_NORMAL
2533 ::css::awt::FontWeight::NORMAL, // WEIGHT_MEDIUM
2534 ::css::awt::FontWeight::SEMIBOLD, // WEIGHT_SEMIBOLD
2535 ::css::awt::FontWeight::BOLD, // WEIGHT_BOLD
2536 ::css::awt::FontWeight::ULTRABOLD, // WEIGHT_ULTRABOLD
2537 ::css::awt::FontWeight::BLACK }; // WEIGHT_BLACK
2538 return ::css::uno::makeAny(aWeight[nWeight]);
2539 }
2540
2541 // static
mapFontWeight(::css::uno::Any const & rWeight)2542 ::FontWeight Document::mapFontWeight(::css::uno::Any const & rWeight)
2543 {
2544 float nWeight = ::css::awt::FontWeight::NORMAL;
2545 rWeight >>= nWeight;
2546 return nWeight <= ::css::awt::FontWeight::DONTKNOW ? WEIGHT_DONTKNOW
2547 : nWeight <= ::css::awt::FontWeight::THIN ? WEIGHT_THIN
2548 : nWeight <= ::css::awt::FontWeight::ULTRALIGHT ? WEIGHT_ULTRALIGHT
2549 : nWeight <= ::css::awt::FontWeight::LIGHT ? WEIGHT_LIGHT
2550 : nWeight <= ::css::awt::FontWeight::SEMILIGHT ? WEIGHT_SEMILIGHT
2551 : nWeight <= ::css::awt::FontWeight::NORMAL ? WEIGHT_NORMAL
2552 : nWeight <= ::css::awt::FontWeight::SEMIBOLD ? WEIGHT_SEMIBOLD
2553 : nWeight <= ::css::awt::FontWeight::BOLD ? WEIGHT_BOLD
2554 : nWeight <= ::css::awt::FontWeight::ULTRABOLD ? WEIGHT_ULTRABOLD
2555 : WEIGHT_BLACK;
2556 }
2557
2558 }
2559