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