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 // IAccessible2 implementation 2009
1544 			//if ( !m_bCompoundControlChild )
1545 				VCLXAccessibleComponent::ProcessWindowEvent( rVclWindowEvent );
1546 		}
1547 		break;
1548 		default:
1549 			VCLXAccessibleComponent::ProcessWindowEvent( rVclWindowEvent );
1550 	}
1551 }
1552 
1553 // virtual
1554 ::sal_Int32 SAL_CALL Document::getAccessibleChildCount()
1555     throw (::css::uno::RuntimeException)
1556 {
1557     ::comphelper::OExternalLockGuard aGuard(this);
1558     init();
1559     return m_aVisibleEnd - m_aVisibleBegin;
1560 }
1561 
1562 // virtual
1563 ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL
1564 Document::getAccessibleChild(::sal_Int32 i)
1565     throw (::css::lang::IndexOutOfBoundsException,
1566            ::css::uno::RuntimeException)
1567 {
1568     ::comphelper::OExternalLockGuard aGuard(this);
1569     init();
1570     if (i < 0 || i >= m_aVisibleEnd - m_aVisibleBegin)
1571         throw ::css::lang::IndexOutOfBoundsException(
1572             ::rtl::OUString(
1573                 RTL_CONSTASCII_USTRINGPARAM(
1574                     "textwindowaccessibility.cxx:"
1575                     " Document::getAccessibleChild")),
1576             static_cast< ::css::uno::XWeak * >(this));
1577     return getAccessibleChild(m_aVisibleBegin
1578                               + static_cast< Paragraphs::size_type >(i));
1579 }
1580 
1581 // virtual
1582 ::sal_Int16 SAL_CALL Document::getAccessibleRole()
1583     throw (::css::uno::RuntimeException)
1584 {
1585     return ::css::accessibility::AccessibleRole::TEXT_FRAME;
1586 }
1587 
1588 // virtual
1589 ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL
1590 Document::getAccessibleAtPoint(::css::awt::Point const & rPoint)
1591     throw (::css::uno::RuntimeException)
1592 {
1593     ::comphelper::OExternalLockGuard aGuard(this);
1594     init();
1595     if (rPoint.X >= 0
1596         && rPoint.X < m_rView.GetWindow()->GetOutputSizePixel().Width()
1597         && rPoint.Y >= 0 && rPoint.Y < m_nViewHeight)
1598     {
1599         ::sal_Int32 nOffset = m_nViewOffset + rPoint.Y; // XXX  numeric overflow
1600         ::sal_Int32 nPos = m_nViewOffset - m_nVisibleBeginOffset;
1601         for (Paragraphs::iterator aIt(m_aVisibleBegin); aIt != m_aVisibleEnd;
1602              ++aIt)
1603         {
1604             nPos += aIt->getHeight(); // XXX  numeric overflow
1605             if (nOffset < nPos)
1606                 return getAccessibleChild(aIt);
1607         }
1608     }
1609     return 0;
1610 }
1611 void Document::FillAccessibleStateSet( utl::AccessibleStateSetHelper& rStateSet )
1612 {
1613 	VCLXAccessibleComponent::FillAccessibleStateSet( rStateSet );
1614 	if (!m_rView.IsReadOnly())
1615 		rStateSet.AddState( ::css::accessibility::AccessibleStateType::EDITABLE );
1616 }
1617 
1618 void	Document::FillAccessibleRelationSet( utl::AccessibleRelationSetHelper& rRelationSet )
1619 {
1620 	if( getAccessibleParent()->getAccessibleContext()->getAccessibleRole() == ::css::accessibility::AccessibleRole::SCROLL_PANE )
1621 	{
1622 		::css::uno::Sequence< ::css::uno::Reference< ::css::uno::XInterface > > aSequence(1);
1623 		aSequence[0] = getAccessibleParent();
1624 		rRelationSet.AddRelation( ::css::accessibility::AccessibleRelation( ::css::accessibility::AccessibleRelationType::MEMBER_OF, aSequence ) );
1625 	}
1626 	else
1627 	{
1628 		 VCLXAccessibleComponent::FillAccessibleRelationSet(rRelationSet);
1629 	}
1630 }
1631 // virtual
1632 void SAL_CALL Document::disposing()
1633 {
1634     m_aEngineListener.endListening();
1635     m_aViewListener.endListening();
1636     if (m_xParagraphs.get() != 0)
1637         disposeParagraphs();
1638     VCLXAccessibleComponent::disposing();
1639 }
1640 
1641 // virtual
1642 void Document::Notify(::SfxBroadcaster &, ::SfxHint const & rHint)
1643 {
1644     if (rHint.ISA(::TextHint))
1645     {
1646         ::TextHint const & rTextHint
1647               = static_cast< ::TextHint const & >(rHint);
1648         switch (rTextHint.GetId())
1649         {
1650         case TEXT_HINT_PARAINSERTED:
1651         case TEXT_HINT_PARAREMOVED:
1652             // TEXT_HINT_PARAINSERTED and TEXT_HINT_PARAREMOVED are sent at
1653             // "unsafe" times (when the text engine has not yet re-formatted its
1654             // content), so that for example calling ::TextEngine::GetTextHeight
1655             // from within the code that handles TEXT_HINT_PARAINSERTED causes
1656             // trouble within the text engine.  Therefore, these hints are just
1657             // buffered until a following ::TextEngine::FormatDoc causes a
1658             // TEXT_HINT_TEXTFORMATTED to come in:
1659         case TEXT_HINT_FORMATPARA:
1660             // ::TextEngine::FormatDoc sends a sequence of
1661             // TEXT_HINT_FORMATPARAs, followed by an optional
1662             // TEXT_HINT_TEXTHEIGHTCHANGED, followed in all cases by one
1663             // TEXT_HINT_TEXTFORMATTED.  Only the TEXT_HINT_FORMATPARAs contain
1664             // the the numbers of the affected paragraphs, but they are sent
1665             // before the changes are applied.  Therefore, TEXT_HINT_FORMATPARAs
1666             // are just buffered until another hint comes in:
1667             {
1668                 ::osl::MutexGuard aInternalGuard(GetMutex());
1669                 if (!isAlive())
1670                     break;
1671 
1672                 m_aParagraphNotifications.push(rTextHint);
1673                 break;
1674             }
1675         case TEXT_HINT_TEXTFORMATTED:
1676         case TEXT_HINT_TEXTHEIGHTCHANGED:
1677         case TEXT_HINT_MODIFIED:
1678             {
1679                 ::osl::MutexGuard aInternalGuard(GetMutex());
1680                 if (!isAlive())
1681                     break;
1682                 handleParagraphNotifications();
1683                 break;
1684             }
1685         case TEXT_HINT_VIEWSCROLLED:
1686             {
1687                 ::osl::MutexGuard aInternalGuard(GetMutex());
1688                 if (!isAlive())
1689                     break;
1690                 handleParagraphNotifications();
1691 
1692                 ::sal_Int32 nOffset = static_cast< ::sal_Int32 >(
1693                     m_rView.GetStartDocPos().Y());
1694                     // XXX  numeric overflow
1695                 if (nOffset != m_nViewOffset)
1696                 {
1697                     m_nViewOffset = nOffset;
1698 
1699                     Paragraphs::iterator aOldVisibleBegin(
1700                         m_aVisibleBegin);
1701                     Paragraphs::iterator aOldVisibleEnd(m_aVisibleEnd);
1702 
1703                     determineVisibleRange();
1704 
1705                     notifyVisibleRangeChanges(aOldVisibleBegin,
1706                                                 aOldVisibleEnd,
1707                                                 m_xParagraphs->end());
1708                 }
1709                 break;
1710             }
1711         case TEXT_HINT_VIEWSELECTIONCHANGED:
1712             {
1713                 ::osl::MutexGuard aInternalGuard(GetMutex());
1714                 if (!isAlive())
1715                     break;
1716 
1717                 if (m_aParagraphNotifications.empty())
1718                 {
1719                     handleSelectionChangeNotification();
1720                 }
1721                 else
1722                 {
1723                     // TEXT_HINT_VIEWSELECTIONCHANGED is sometimes sent at
1724                     // "unsafe" times (when the text engine has not yet re-
1725                     // formatted its content), so that for example calling
1726                     // ::TextEngine::GetTextHeight from within the code that
1727                     // handles a previous TEXT_HINT_PARAINSERTED causes
1728                     // trouble within the text engine.  Therefore, these
1729                     // hints are just buffered (along with
1730                     // TEXT_HINT_PARAINSERTED/REMOVED/FORMATPARA) until a
1731                     // following ::TextEngine::FormatDoc causes a
1732                     // TEXT_HINT_TEXTFORMATTED to come in:
1733                     m_bSelectionChangedNotification = true;
1734                 }
1735                 break;
1736             }
1737         }
1738     }
1739 }
1740 
1741 IMPL_LINK(Document, WindowEventHandler, ::VclSimpleEvent *, pEvent)
1742 {
1743     switch (pEvent->GetId())
1744     {
1745     case VCLEVENT_WINDOW_RESIZE:
1746         {
1747             ::osl::MutexGuard aInternalGuard(GetMutex());
1748             if (!isAlive())
1749                 break;
1750 
1751             ::sal_Int32 nHeight = static_cast< ::sal_Int32 >(
1752                 m_rView.GetWindow()->GetOutputSizePixel().Height());
1753                 // XXX  numeric overflow
1754             if (nHeight != m_nViewHeight)
1755             {
1756                 m_nViewHeight = nHeight;
1757 
1758                 Paragraphs::iterator aOldVisibleBegin(m_aVisibleBegin);
1759                 Paragraphs::iterator aOldVisibleEnd(m_aVisibleEnd);
1760 
1761                 determineVisibleRange();
1762 
1763                 notifyVisibleRangeChanges(aOldVisibleBegin, aOldVisibleEnd,
1764                                             m_xParagraphs->end());
1765             }
1766             break;
1767         }
1768     case VCLEVENT_WINDOW_GETFOCUS:
1769         {
1770             ::osl::MutexGuard aInternalGuard(GetMutex());
1771             if (!isAlive())
1772                 break;
1773 			//to enable the PARAGRAPH to get focus for multiline edit
1774 			::sal_Int32 count = getAccessibleChildCount();
1775 			::sal_Bool bEmpty = m_aFocused == m_aVisibleEnd && count == 1;
1776             if ((m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd) || bEmpty)
1777             {
1778 				Paragraphs::iterator m_aTemp = bEmpty ? m_aVisibleBegin : m_aFocused;
1779                 ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(m_aTemp));
1780 				if (xParagraph.is())
1781 				{
1782 					xParagraph->notifyEvent(
1783 						::css::accessibility::AccessibleEventId::
1784 						STATE_CHANGED,
1785 						::css::uno::Any(),
1786 						::css::uno::makeAny(
1787 							::css::accessibility::AccessibleStateType::
1788 							FOCUSED));
1789 				}
1790             }
1791 			/*
1792                 ::rtl::Reference< ParagraphImpl > xParagraph(
1793                     getParagraph(m_aFocused));
1794                 if (xParagraph.is())
1795                     xParagraph->notifyEvent(
1796                         ::css::accessibility::AccessibleEventId::
1797                         STATE_CHANGED,
1798                         ::css::uno::Any(),
1799                         ::css::uno::makeAny(
1800                             ::css::accessibility::AccessibleStateType::
1801                             FOCUSED));
1802 			*/
1803             break;
1804         }
1805     case VCLEVENT_WINDOW_LOSEFOCUS:
1806         {
1807             ::osl::MutexGuard aInternalGuard(GetMutex());
1808             if (!isAlive())
1809                 break;
1810 			//to enable the PARAGRAPH to get focus for multiline edit
1811 			::sal_Int32 count = getAccessibleChildCount();
1812 			::sal_Bool bEmpty = m_aFocused == m_aVisibleEnd && count == 1;
1813             if ((m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd) || bEmpty)
1814             {
1815 				Paragraphs::iterator m_aTemp = bEmpty ? m_aVisibleBegin : m_aFocused;
1816                 ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(m_aTemp));
1817                 if (xParagraph.is())
1818                     xParagraph->notifyEvent(
1819                         ::css::accessibility::AccessibleEventId::
1820                         STATE_CHANGED,
1821                         ::css::uno::makeAny(
1822                             ::css::accessibility::AccessibleStateType::
1823                             FOCUSED),
1824                         ::css::uno::Any());
1825             }
1826 
1827 			/*
1828             if (m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd)
1829             {
1830                 ::rtl::Reference< ParagraphImpl > xParagraph(
1831                     getParagraph(m_aFocused));
1832                 if (xParagraph.is())
1833                     xParagraph->notifyEvent(
1834                         ::css::accessibility::AccessibleEventId::
1835                         STATE_CHANGED,
1836                         ::css::uno::makeAny(
1837                             ::css::accessibility::AccessibleStateType::
1838                             FOCUSED),
1839                         ::css::uno::Any());
1840             }
1841 			*/
1842             break;
1843         }
1844     }
1845     return 0;
1846 }
1847 
1848 void Document::init()
1849 {
1850     if (m_xParagraphs.get() == 0)
1851     {
1852         ::sal_uLong nCount = m_rEngine.GetParagraphCount();
1853         ::std::auto_ptr< Paragraphs > p(new Paragraphs);
1854         p->reserve(static_cast< Paragraphs::size_type >(nCount));
1855             // numeric overflow is harmless here
1856         for (::sal_uLong i = 0; i < nCount; ++i)
1857             p->push_back(ParagraphInfo(static_cast< ::sal_Int32 >(
1858                                            m_rEngine.GetTextHeight(i))));
1859                 // XXX  numeric overflow
1860         m_nViewOffset = static_cast< ::sal_Int32 >(
1861             m_rView.GetStartDocPos().Y()); // XXX  numeric overflow
1862         m_nViewHeight = static_cast< ::sal_Int32 >(
1863             m_rView.GetWindow()->GetOutputSizePixel().Height());
1864             // XXX  numeric overflow
1865         m_xParagraphs = p;
1866         determineVisibleRange();
1867         m_nSelectionFirstPara = -1;
1868         m_nSelectionFirstPos = -1;
1869         m_nSelectionLastPara = -1;
1870         m_nSelectionLastPos = -1;
1871         m_aFocused = m_xParagraphs->end();
1872         m_bSelectionChangedNotification = false;
1873         m_aEngineListener.startListening(m_rEngine);
1874         m_aViewListener.startListening(*m_rView.GetWindow());
1875     }
1876 }
1877 
1878 ::rtl::Reference< ParagraphImpl >
1879 Document::getParagraph(Paragraphs::iterator const & rIt)
1880 {
1881     return static_cast< ParagraphImpl * >(
1882         ::css::uno::Reference< ::css::accessibility::XAccessible >(
1883             rIt->getParagraph()).get());
1884 }
1885 
1886 ::css::uno::Reference< ::css::accessibility::XAccessible >
1887 Document::getAccessibleChild(Paragraphs::iterator const & rIt)
1888 {
1889     ::css::uno::Reference< ::css::accessibility::XAccessible > xParagraph(
1890         rIt->getParagraph());
1891     if (!xParagraph.is())
1892     {
1893         xParagraph = new Paragraph(this, rIt - m_xParagraphs->begin());
1894         rIt->setParagraph(xParagraph);
1895     }
1896     return xParagraph;
1897 }
1898 
1899 void Document::determineVisibleRange()
1900 {
1901     m_aVisibleBegin = m_xParagraphs->end();
1902     m_aVisibleEnd = m_aVisibleBegin;
1903     ::sal_Int32 nPos = 0;
1904     for (Paragraphs::iterator aIt = m_xParagraphs->begin();;)
1905     {
1906         if (aIt == m_xParagraphs->end())
1907         {
1908             m_nVisibleBeginOffset = 0;
1909             break;
1910         }
1911         ::sal_Int32 nOldPos = nPos;
1912         nPos += aIt->getHeight(); // XXX  numeric overflow
1913         if (m_aVisibleBegin == m_xParagraphs->end() && nPos >= m_nViewOffset)
1914         {
1915             m_aVisibleBegin = aIt;
1916             m_nVisibleBeginOffset = m_nViewOffset - nOldPos;
1917         }
1918         ++aIt;
1919         if (m_aVisibleBegin != m_xParagraphs->end()
1920             && (aIt == m_xParagraphs->end()
1921                 || nPos >= m_nViewOffset + m_nViewHeight))
1922             // XXX  numeric overflow
1923         {
1924             m_aVisibleEnd = aIt;
1925             break;
1926         }
1927     }
1928 }
1929 
1930 void Document::notifyVisibleRangeChanges(
1931     Paragraphs::iterator const & rOldVisibleBegin,
1932     Paragraphs::iterator const & rOldVisibleEnd,
1933     Paragraphs::iterator const & rInserted)
1934 {
1935     // XXX  Replace this code that determines which paragraphs have changed from
1936     // invisible to visible or vice versa with a better algorithm.
1937     {for (Paragraphs::iterator aIt(rOldVisibleBegin); aIt != rOldVisibleEnd;
1938           ++aIt)
1939         if (aIt != rInserted
1940             && (aIt < m_aVisibleBegin || aIt >= m_aVisibleEnd))
1941             NotifyAccessibleEvent(
1942                 ::css::accessibility::AccessibleEventId::
1943                 CHILD,
1944                 ::css::uno::makeAny(getAccessibleChild(aIt)),
1945                 ::css::uno::Any());
1946     }
1947     {for (Paragraphs::iterator aIt(m_aVisibleBegin); aIt != m_aVisibleEnd;
1948           ++aIt)
1949         if (aIt == rInserted
1950             || aIt < rOldVisibleBegin || aIt >= rOldVisibleEnd)
1951             NotifyAccessibleEvent(
1952                 ::css::accessibility::AccessibleEventId::
1953                 CHILD,
1954                 ::css::uno::Any(),
1955                 ::css::uno::makeAny(getAccessibleChild(aIt)));
1956     }
1957 }
1958 
1959 void
1960 Document::changeParagraphText(::sal_uLong nNumber, ::sal_uInt16 nBegin, ::sal_uInt16 nEnd,
1961                               bool bCut, bool bPaste,
1962                               ::rtl::OUString const & rText)
1963 {
1964     m_rView.SetSelection(::TextSelection(::TextPaM(nNumber, nBegin),
1965                                          ::TextPaM(nNumber, nEnd)));
1966     if (bCut)
1967         m_rView.Cut();
1968     else if (nBegin != nEnd)
1969         m_rView.DeleteSelected();
1970     if (bPaste)
1971         m_rView.Paste();
1972     else if (rText.getLength() != 0)
1973         m_rView.InsertText(rText);
1974 }
1975 
1976 void Document::handleParagraphNotifications()
1977 {
1978     while (!m_aParagraphNotifications.empty())
1979     {
1980         ::TextHint aHint(m_aParagraphNotifications.front());
1981         m_aParagraphNotifications.pop();
1982         switch (aHint.GetId())
1983         {
1984         case TEXT_HINT_PARAINSERTED:
1985             {
1986                 ::sal_uLong n = aHint.GetValue();
1987                 OSL_ENSURE(n <= m_xParagraphs->size(),
1988                            "bad TEXT_HINT_PARAINSERTED event");
1989 
1990                 // Save the values of old iterators (the iterators themselves
1991                 // will get invalidated), and adjust the old values so that they
1992                 // reflect the insertion of the new paragraph:
1993                 Paragraphs::size_type nOldVisibleBegin
1994                     = m_aVisibleBegin - m_xParagraphs->begin();
1995                 Paragraphs::size_type nOldVisibleEnd
1996                     = m_aVisibleEnd - m_xParagraphs->begin();
1997                 Paragraphs::size_type nOldFocused
1998                     = m_aFocused - m_xParagraphs->begin();
1999                 if (n <= nOldVisibleBegin)
2000                     ++nOldVisibleBegin; // XXX  numeric overflow
2001                 if (n <= nOldVisibleEnd)
2002                     ++nOldVisibleEnd; // XXX  numeric overflow
2003                 if (n <= nOldFocused)
2004                     ++nOldFocused; // XXX  numeric overflow
2005                 if (sal::static_int_cast<sal_Int32>(n) <= m_nSelectionFirstPara)
2006                     ++m_nSelectionFirstPara; // XXX  numeric overflow
2007                 if (sal::static_int_cast<sal_Int32>(n) <= m_nSelectionLastPara)
2008                     ++m_nSelectionLastPara; // XXX  numeric overflow
2009 
2010                 Paragraphs::iterator aIns(
2011                     m_xParagraphs->insert(
2012                         m_xParagraphs->begin() + n,
2013                         ParagraphInfo(static_cast< ::sal_Int32 >(
2014                                           m_rEngine.GetTextHeight(n)))));
2015                     // XXX  numeric overflow (2x)
2016 
2017                 determineVisibleRange();
2018                 m_aFocused = m_xParagraphs->begin() + nOldFocused;
2019 
2020                 for (Paragraphs::iterator aIt(aIns);;)
2021                 {
2022                     ++aIt;
2023                     if (aIt == m_xParagraphs->end())
2024                         break;
2025                     ::rtl::Reference< ParagraphImpl > xParagraph(
2026                         getParagraph(aIt));
2027                     if (xParagraph.is())
2028                         xParagraph->numberChanged(true);
2029                 }
2030 
2031                 notifyVisibleRangeChanges(
2032                     m_xParagraphs->begin() + nOldVisibleBegin,
2033                     m_xParagraphs->begin() + nOldVisibleEnd, aIns);
2034                 break;
2035             }
2036         case TEXT_HINT_PARAREMOVED:
2037             {
2038                 ::sal_uLong n = aHint.GetValue();
2039                 if (n == TEXT_PARA_ALL)
2040                 {
2041                     {for (Paragraphs::iterator aIt(m_aVisibleBegin);
2042                           aIt != m_aVisibleEnd; ++aIt)
2043                         NotifyAccessibleEvent(
2044                             ::css::accessibility::AccessibleEventId::
2045                             CHILD,
2046                             ::css::uno::makeAny(getAccessibleChild(aIt)),
2047                             ::css::uno::Any());
2048                     }
2049                     disposeParagraphs();
2050                     m_xParagraphs->clear();
2051                     determineVisibleRange();
2052                     m_nSelectionFirstPara = -1;
2053                     m_nSelectionFirstPos = -1;
2054                     m_nSelectionLastPara = -1;
2055                     m_nSelectionLastPos = -1;
2056                     m_aFocused = m_xParagraphs->end();
2057                 }
2058                 else
2059                 {
2060                     OSL_ENSURE(n < m_xParagraphs->size(),
2061                                "Bad TEXT_HINT_PARAREMOVED event");
2062 
2063                     Paragraphs::iterator aIt(m_xParagraphs->begin() + n);
2064                         // numeric overflow cannot occur
2065 
2066                     // Save the values of old iterators (the iterators
2067                     // themselves will get invalidated), and adjust the old
2068                     // values so that they reflect the removal of the paragraph:
2069                     Paragraphs::size_type nOldVisibleBegin
2070                         = m_aVisibleBegin - m_xParagraphs->begin();
2071                     Paragraphs::size_type nOldVisibleEnd
2072                         = m_aVisibleEnd - m_xParagraphs->begin();
2073                     bool bWasVisible
2074                         = nOldVisibleBegin <= n && n < nOldVisibleEnd;
2075                     Paragraphs::size_type nOldFocused
2076                         = m_aFocused - m_xParagraphs->begin();
2077                     bool bWasFocused = aIt == m_aFocused;
2078                     if (n < nOldVisibleBegin)
2079                         --nOldVisibleBegin;
2080                     if (n < nOldVisibleEnd)
2081                         --nOldVisibleEnd;
2082                     if (n < nOldFocused)
2083                         --nOldFocused;
2084                     if (sal::static_int_cast<sal_Int32>(n) < m_nSelectionFirstPara)
2085                         --m_nSelectionFirstPara;
2086                     else if (sal::static_int_cast<sal_Int32>(n) == m_nSelectionFirstPara)
2087                     {
2088                         if (m_nSelectionFirstPara == m_nSelectionLastPara)
2089                         {
2090                             m_nSelectionFirstPara = -1;
2091                             m_nSelectionFirstPos = -1;
2092                             m_nSelectionLastPara = -1;
2093                             m_nSelectionLastPos = -1;
2094                         }
2095                         else
2096                         {
2097                             ++m_nSelectionFirstPara;
2098                             m_nSelectionFirstPos = 0;
2099                         }
2100                     }
2101                     if (sal::static_int_cast<sal_Int32>(n) < m_nSelectionLastPara)
2102                         --m_nSelectionLastPara;
2103                     else if (sal::static_int_cast<sal_Int32>(n) == m_nSelectionLastPara)
2104                     {
2105                         OSL_ENSURE(m_nSelectionFirstPara < m_nSelectionLastPara,
2106                                    "logic error");
2107                         --m_nSelectionLastPara;
2108                         m_nSelectionLastPos = 0x7FFFFFFF;
2109                     }
2110 
2111                     ::css::uno::Reference< ::css::accessibility::XAccessible >
2112                           xStrong;
2113                     if (bWasVisible)
2114                         xStrong = getAccessibleChild(aIt);
2115                     ::css::uno::WeakReference<
2116                           ::css::accessibility::XAccessible > xWeak(
2117                               aIt->getParagraph());
2118                     aIt = m_xParagraphs->erase(aIt);
2119 
2120                     determineVisibleRange();
2121                     m_aFocused = bWasFocused ? m_xParagraphs->end()
2122                         : m_xParagraphs->begin() + nOldFocused;
2123 
2124                     for (; aIt != m_xParagraphs->end(); ++aIt)
2125                     {
2126                         ::rtl::Reference< ParagraphImpl > xParagraph(
2127                             getParagraph(aIt));
2128                         if (xParagraph.is())
2129                             xParagraph->numberChanged(false);
2130                     }
2131 
2132                     if (bWasVisible)
2133                         NotifyAccessibleEvent(
2134                             ::css::accessibility::AccessibleEventId::
2135                             CHILD,
2136                             ::css::uno::makeAny(getAccessibleChild(aIt)),
2137                             ::css::uno::Any());
2138 
2139                     ::css::uno::Reference< ::css::lang::XComponent > xComponent(
2140                         xWeak.get(), ::css::uno::UNO_QUERY);
2141                     if (xComponent.is())
2142                         xComponent->dispose();
2143 
2144                     notifyVisibleRangeChanges(
2145                         m_xParagraphs->begin() + nOldVisibleBegin,
2146                         m_xParagraphs->begin() + nOldVisibleEnd,
2147                         m_xParagraphs->end());
2148                 }
2149                 break;
2150             }
2151         case TEXT_HINT_FORMATPARA:
2152             {
2153                 ::sal_uLong n = aHint.GetValue();
2154                 OSL_ENSURE(n < m_xParagraphs->size(),
2155                            "Bad TEXT_HINT_FORMATPARA event");
2156 
2157                 (*m_xParagraphs)[static_cast< Paragraphs::size_type >(n)].
2158                     changeHeight(static_cast< ::sal_Int32 >(
2159                                      m_rEngine.GetTextHeight(n)));
2160                     // XXX  numeric overflow
2161                 Paragraphs::iterator aOldVisibleBegin(m_aVisibleBegin);
2162                 Paragraphs::iterator aOldVisibleEnd(m_aVisibleEnd);
2163                 determineVisibleRange();
2164                 notifyVisibleRangeChanges(aOldVisibleBegin, aOldVisibleEnd,
2165                                           m_xParagraphs->end());
2166 
2167                 if (n < m_xParagraphs->size())
2168                 {
2169                     Paragraphs::iterator aIt(m_xParagraphs->begin() + n);
2170                     ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(aIt));
2171                     if (xParagraph.is())
2172                         xParagraph->textChanged();
2173                 }
2174                 break;
2175             }
2176         default:
2177             OSL_ENSURE(false, "bad buffered hint");
2178             break;
2179         }
2180     }
2181     if (m_bSelectionChangedNotification)
2182     {
2183         m_bSelectionChangedNotification = false;
2184         handleSelectionChangeNotification();
2185     }
2186 }
2187 
2188 ::sal_Int32 Document::getSelectionType(::sal_Int32 nNewFirstPara, ::sal_Int32 nNewFirstPos, ::sal_Int32 nNewLastPara, ::sal_Int32 nNewLastPos)
2189 {
2190 	if (m_nSelectionFirstPara == -1)
2191 		return -1;
2192 	::sal_Int32 Osp = m_nSelectionFirstPara, Osl = m_nSelectionFirstPos, Oep = m_nSelectionLastPara, Oel = m_nSelectionLastPos;
2193 	::sal_Int32 Nsp = nNewFirstPara, Nsl = nNewFirstPos, Nep = nNewLastPara, Nel = nNewLastPos;
2194 	TextPaM Ns(Nsp, sal_uInt16(Nsl));
2195 	TextPaM Ne(Nep, sal_uInt16(Nel));
2196 	TextPaM Os(Osp, sal_uInt16(Osl));
2197 	TextPaM Oe(Oep, sal_uInt16(Oel));
2198 
2199 	if (Os == Oe && Ns == Ne)
2200 	{
2201 		//only caret moves.
2202 		return 1;
2203 	}
2204 	else if (Os == Oe && Ns != Ne)
2205 	{
2206 		//old has no selection but new has selection
2207 		return 2;
2208 	}
2209 	else if (Os != Oe && Ns == Ne)
2210 	{
2211 		//old has selection but new has no selection.
2212 		return 3;
2213 	}
2214 	else if (Os != Oe && Ns != Ne && Osp == Nsp && Osl == Nsl)
2215 	{
2216 		//both old and new have selections.
2217 		if (Oep == Nep )
2218 		{
2219 			//Send text_selection_change event on Nep
2220 
2221 			return 4;
2222 		}
2223 		else if (Oep < Nep)
2224 		{
2225 			//all the following examples like 1,2->1,3 means that old start select para is 1, old end select para is 2,
2226 			// then press shift up, the new start select para is 1, new end select para is 3;
2227 			//for example, 1, 2 -> 1, 3; 4,1 -> 4, 7; 4,1 -> 4, 2; 4,4->4,5
2228 			if (Nep >= Nsp)
2229 			{
2230 				// 1, 2 -> 1, 3; 4, 1 -> 4, 7; 4,4->4,5;
2231 				if (Oep < Osp)
2232 				{
2233 					// 4,1 -> 4,7;
2234 					return 5;
2235 				}
2236 				else if (Oep >= Osp)
2237 				{
2238 					// 1, 2 -> 1, 3; 4,4->4,5;
2239 					return 6;
2240 				}
2241 			}
2242 			else
2243 			{
2244 				// 4,1 -> 4,2,
2245 				if (Oep < Osp)
2246 				{
2247 					// 4,1 -> 4,2,
2248 					return 7;
2249 				}
2250 				else if (Oep >= Osp)
2251 				{
2252 					// no such condition. Oep > Osp = Nsp > Nep
2253 				}
2254 			}
2255 		}
2256 		else if (Oep > Nep)
2257 		{
2258 			// 3,2 -> 3,1; 4,7 -> 4,1; 4, 7 -> 4,6; 4,4 -> 4,3
2259 			if (Nep >= Nsp)
2260 			{
2261 				// 4,7 -> 4,6
2262 				if (Oep <= Osp)
2263 				{
2264 					//no such condition, Oep<Osp=Nsp <= Nep
2265 				}
2266 				else if (Oep > Osp)
2267 				{
2268 					// 4,7 ->4,6
2269 					return 8;
2270 				}
2271 			}
2272 			else
2273 			{
2274 				// 3,2 -> 3,1, 4,7 -> 4,1; 4,4->4,3
2275 				if (Oep <= Osp)
2276 				{
2277 					// 3,2 -> 3,1; 4,4->4,3
2278 					return 9;
2279 				}
2280 				else if (Oep > Osp)
2281 				{
2282 					// 4,7 -> 4,1
2283 					return 10;
2284 				}
2285 			}
2286 		}
2287 	}
2288 	return -1;
2289 }
2290 
2291 
2292 void Document::sendEvent(::sal_Int32 start, ::sal_Int32 end, ::sal_Int16 nEventId)
2293 {
2294 	 Paragraphs::iterator aEnd = ::std::min(m_xParagraphs->begin() + end + 1, m_aVisibleEnd);
2295 	for (Paragraphs::iterator aIt = ::std::max(m_xParagraphs->begin() + start, m_aVisibleBegin);
2296 	     aIt < aEnd; ++aIt)
2297 	{
2298 	    ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(aIt));
2299 	    if (xParagraph.is())
2300 	        xParagraph->notifyEvent(
2301 			nEventId,
2302 	            ::css::uno::Any(), ::css::uno::Any());
2303 	}
2304 }
2305 
2306 void Document::handleSelectionChangeNotification()
2307 {
2308     ::TextSelection const & rSelection = m_rView.GetSelection();
2309     OSL_ENSURE(rSelection.GetStart().GetPara() < m_xParagraphs->size()
2310                && rSelection.GetEnd().GetPara() < m_xParagraphs->size(),
2311                "bad TEXT_HINT_VIEWSELECTIONCHANGED event");
2312     ::sal_Int32 nNewFirstPara
2313           = static_cast< ::sal_Int32 >(rSelection.GetStart().GetPara());
2314     ::sal_Int32 nNewFirstPos
2315           = static_cast< ::sal_Int32 >(rSelection.GetStart().GetIndex());
2316         // XXX  numeric overflow
2317     ::sal_Int32 nNewLastPara
2318           = static_cast< ::sal_Int32 >(rSelection.GetEnd().GetPara());
2319     ::sal_Int32 nNewLastPos
2320           = static_cast< ::sal_Int32 >(rSelection.GetEnd().GetIndex());
2321         // XXX  numeric overflow
2322 
2323     // Lose focus:
2324     Paragraphs::iterator aIt(m_xParagraphs->begin() + nNewLastPara);
2325     if (m_aFocused != m_xParagraphs->end() && m_aFocused != aIt
2326         && m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd)
2327     {
2328         ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(m_aFocused));
2329         if (xParagraph.is())
2330             xParagraph->notifyEvent(
2331                 ::css::accessibility::AccessibleEventId::
2332                 STATE_CHANGED,
2333                 ::css::uno::makeAny(
2334                     ::css::accessibility::AccessibleStateType::FOCUSED),
2335                 ::css::uno::Any());
2336     }
2337 
2338     // Gain focus and update cursor position:
2339     if (aIt >= m_aVisibleBegin && aIt < m_aVisibleEnd
2340         && (aIt != m_aFocused
2341             || nNewLastPara != m_nSelectionLastPara
2342             || nNewLastPos != m_nSelectionLastPos))
2343     {
2344         ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(aIt));
2345         if (xParagraph.is())
2346         {
2347 		//disable the first event when user types in empty field.
2348 		::sal_Int32 count = getAccessibleChildCount();
2349 		::sal_Bool bEmpty = count > 1;
2350             //if (aIt != m_aFocused)
2351 			if (aIt != m_aFocused && bEmpty)
2352                 xParagraph->notifyEvent(
2353                     ::css::accessibility::AccessibleEventId::
2354                     STATE_CHANGED,
2355                     ::css::uno::Any(),
2356                     ::css::uno::makeAny(
2357                         ::css::accessibility::AccessibleStateType::FOCUSED));
2358             if (nNewLastPara != m_nSelectionLastPara
2359                 || nNewLastPos != m_nSelectionLastPos)
2360                 xParagraph->notifyEvent(
2361                     ::css::accessibility::AccessibleEventId::
2362                     CARET_CHANGED,
2363                     ::css::uno::makeAny< ::sal_Int32 >(
2364                         nNewLastPara == m_nSelectionLastPara
2365                         ? m_nSelectionLastPos : 0),
2366                     ::css::uno::makeAny(nNewLastPos));
2367         }
2368     }
2369     m_aFocused = aIt;
2370 
2371     ::sal_Int32 nMin;
2372     ::sal_Int32 nMax;
2373     ::sal_Int32 ret = getSelectionType(nNewFirstPara, nNewFirstPos, nNewLastPara, nNewLastPos);
2374 	switch (ret)
2375 	{
2376 		case -1:
2377 			{
2378 				//no event
2379 			}
2380 			break;
2381 		case 1:
2382 			{
2383 				//only caret moved, already handled in above
2384 			}
2385 			break;
2386 		case 2:
2387 			{
2388 				//old has no selection but new has selection
2389 				nMin = ::std::min(nNewFirstPara, nNewLastPara);
2390 				nMax = ::std::max(nNewFirstPara, nNewLastPara);
2391 				sendEvent(nMin, nMax,  ::css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2392 				sendEvent(nMin, nMax,  ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2393 			}
2394 			break;
2395 		case 3:
2396 			{
2397 				//old has selection but new has no selection.
2398 				nMin = ::std::min(m_nSelectionFirstPara, m_nSelectionLastPara);
2399 				nMax = ::std::max(m_nSelectionFirstPara, m_nSelectionLastPara);
2400 				sendEvent(nMin, nMax,  ::css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2401 				sendEvent(nMin, nMax,  ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2402 			}
2403 			break;
2404 		case 4:
2405 			{
2406 				//Send text_selection_change event on Nep
2407 				sendEvent(nNewLastPara, nNewLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2408 			}
2409 			break;
2410 		case 5:
2411 			{
2412 				// 4, 1 -> 4, 7
2413 				sendEvent(m_nSelectionLastPara, m_nSelectionFirstPara-1, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2414 				sendEvent(nNewFirstPara+1, nNewLastPara, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2415 
2416 				sendEvent(m_nSelectionLastPara, nNewLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2417 			}
2418 			break;
2419 		case 6:
2420 			{
2421 				// 1, 2 -> 1, 4; 4,4->4,5;
2422 				sendEvent(m_nSelectionLastPara+1, nNewLastPara, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2423 
2424 				sendEvent(m_nSelectionLastPara, nNewLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2425 			}
2426 			break;
2427 		case 7:
2428 			{
2429 				// 4,1 -> 4,3,
2430 				sendEvent(m_nSelectionLastPara +1, nNewLastPara , ::css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2431 
2432 				sendEvent(m_nSelectionLastPara, nNewLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2433 			}
2434 			break;
2435 		case 8:
2436 			{
2437 				// 4,7 ->4,5;
2438 				sendEvent(nNewLastPara + 1, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2439 
2440 				sendEvent(nNewLastPara, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2441 			}
2442 			break;
2443 		case 9:
2444 			{
2445 				// 3,2 -> 3,1; 4,4->4,3
2446 				sendEvent(nNewLastPara, m_nSelectionLastPara - 1, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2447 
2448 				sendEvent(nNewLastPara, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2449 			}
2450 			break;
2451 		case 10:
2452 			{
2453 				// 4,7 -> 4,1
2454 				sendEvent(m_nSelectionFirstPara + 1, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2455 				sendEvent(nNewLastPara, nNewFirstPara - 1, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2456 
2457 				sendEvent(nNewLastPara, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2458 			}
2459 			break;
2460 		default:
2461 			break;
2462 	}
2463 
2464     /*
2465     // Update both old and new selection.  (Regardless of how the two selections
2466     // look like, there will always be two ranges to the left and right of the
2467     // overlap---the overlap and/or the range to the right of it possibly being
2468     // empty.  Only for these two ranges notifications have to be sent.)
2469 
2470     TextPaM aOldTextStart( static_cast< sal_uLong >( m_nSelectionFirstPara ), static_cast< sal_uInt16 >( m_nSelectionFirstPos ) );
2471     TextPaM aOldTextEnd( static_cast< sal_uLong >( m_nSelectionLastPara ), static_cast< sal_uInt16 >( m_nSelectionLastPos ) );
2472     TextPaM aNewTextStart( static_cast< sal_uLong >( nNewFirstPara ), static_cast< sal_uInt16 >( nNewFirstPos ) );
2473     TextPaM aNewTextEnd( static_cast< sal_uLong >( nNewLastPara ), static_cast< sal_uInt16 >( nNewLastPos ) );
2474 
2475     // justify selections
2476     justifySelection( aOldTextStart, aOldTextEnd );
2477     justifySelection( aNewTextStart, aNewTextEnd );
2478 
2479     sal_Int32 nFirst1;
2480     sal_Int32 nLast1;
2481     sal_Int32 nFirst2;
2482     sal_Int32 nLast2;
2483 
2484     if ( m_nSelectionFirstPara == -1 )
2485     {
2486         // old selection not initialized yet => notify events only for new selection (if not empty)
2487         nFirst1 = aNewTextStart.GetPara();
2488         nLast1 = aNewTextEnd.GetPara() + ( aNewTextStart != aNewTextEnd ? 1 : 0 );
2489         nFirst2 = 0;
2490         nLast2 = 0;
2491     }
2492     else if ( aOldTextStart == aOldTextEnd && aNewTextStart == aNewTextEnd )
2493     {
2494         // old an new selection empty => no events
2495         nFirst1 = 0;
2496         nLast1 = 0;
2497         nFirst2 = 0;
2498         nLast2 = 0;
2499     }
2500     else if ( aOldTextStart != aOldTextEnd && aNewTextStart == aNewTextEnd )
2501     {
2502         // old selection not empty + new selection empty => notify events only for old selection
2503         nFirst1 = aOldTextStart.GetPara();
2504         nLast1 = aOldTextEnd.GetPara() + 1;
2505         nFirst2 = 0;
2506         nLast2 = 0;
2507     }
2508     else if ( aOldTextStart == aOldTextEnd && aNewTextStart != aNewTextEnd )
2509     {
2510         // old selection empty + new selection not empty => notify events only for new selection
2511         nFirst1 = aNewTextStart.GetPara();
2512         nLast1 = aNewTextEnd.GetPara() + 1;
2513         nFirst2 = 0;
2514         nLast2 = 0;
2515     }
2516     else
2517     {
2518         // old and new selection not empty => notify events for the two ranges left and right of the overlap
2519         ::std::vector< TextPaM > aTextPaMs(4);
2520         aTextPaMs[0] = aOldTextStart;
2521         aTextPaMs[1] = aOldTextEnd;
2522         aTextPaMs[2] = aNewTextStart;
2523         aTextPaMs[3] = aNewTextEnd;
2524         ::std::sort( aTextPaMs.begin(), aTextPaMs.end() );
2525 
2526         nFirst1 = aTextPaMs[0].GetPara();
2527         nLast1 = aTextPaMs[1].GetPara() + ( aTextPaMs[0] != aTextPaMs[1] ? 1 : 0 );
2528 
2529         nFirst2 = aTextPaMs[2].GetPara();
2530         nLast2 = aTextPaMs[3].GetPara() + ( aTextPaMs[2] != aTextPaMs[3] ? 1 : 0 );
2531 
2532         // adjust overlapping ranges
2533         if ( nLast1 > nFirst2 )
2534             nLast1 = nFirst2;
2535     }
2536 
2537     // notify selection changes
2538     notifySelectionChange( nFirst1, nLast1 );
2539     notifySelectionChange( nFirst2, nLast2 );
2540 	*/
2541     m_nSelectionFirstPara = nNewFirstPara;
2542     m_nSelectionFirstPos = nNewFirstPos;
2543     m_nSelectionLastPara = nNewLastPara;
2544     m_nSelectionLastPos = nNewLastPos;
2545 }
2546 
2547 void Document::notifySelectionChange( sal_Int32 nFirst, sal_Int32 nLast )
2548 {
2549     if ( nFirst < nLast )
2550     {
2551         Paragraphs::iterator aEnd( ::std::min( m_xParagraphs->begin() + nLast, m_aVisibleEnd ) );
2552         for ( Paragraphs::iterator aIt = ::std::max( m_xParagraphs->begin() + nFirst, m_aVisibleBegin ); aIt < aEnd; ++aIt )
2553         {
2554             ::rtl::Reference< ParagraphImpl > xParagraph( getParagraph( aIt ) );
2555             if ( xParagraph.is() )
2556             {
2557                 xParagraph->notifyEvent(
2558                     ::css::accessibility::AccessibleEventId::SELECTION_CHANGED,
2559                     ::css::uno::Any(), ::css::uno::Any() );
2560                 xParagraph->notifyEvent(
2561                     ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED,
2562                     ::css::uno::Any(), ::css::uno::Any() );
2563             }
2564         }
2565     }
2566 }
2567 
2568 void Document::justifySelection( TextPaM& rTextStart, TextPaM& rTextEnd )
2569 {
2570     if ( rTextStart > rTextEnd )
2571     {
2572         TextPaM aTextPaM( rTextStart );
2573         rTextStart = rTextEnd;
2574         rTextEnd = aTextPaM;
2575     }
2576 }
2577 
2578 void Document::disposeParagraphs()
2579 {
2580     for (Paragraphs::iterator aIt(m_xParagraphs->begin());
2581          aIt != m_xParagraphs->end(); ++aIt)
2582     {
2583         ::css::uno::Reference< ::css::lang::XComponent > xComponent(
2584             aIt->getParagraph().get(), ::css::uno::UNO_QUERY);
2585         if (xComponent.is())
2586             xComponent->dispose();
2587     }
2588 }
2589 
2590 // static
2591 ::css::uno::Any Document::mapFontColor(::Color const & rColor)
2592 {
2593     return ::css::uno::makeAny(
2594         static_cast< ::sal_Int32 >(COLORDATA_RGB(rColor.GetColor())));
2595         // FIXME  keep transparency?
2596 }
2597 
2598 // static
2599 ::Color Document::mapFontColor(::css::uno::Any const & rColor)
2600 {
2601     ::sal_Int32 nColor = 0;
2602     rColor >>= nColor;
2603     return ::Color(static_cast< ::ColorData >(nColor));
2604 }
2605 
2606 // static
2607 ::css::uno::Any Document::mapFontWeight(::FontWeight nWeight)
2608 {
2609     // Map from ::FontWeight to ::css:awt::FontWeight, depends on order of
2610     // elements in ::FontWeight (vcl/vclenum.hxx):
2611     static float const aWeight[]
2612         = { ::css::awt::FontWeight::DONTKNOW, // WEIGHT_DONTKNOW
2613             ::css::awt::FontWeight::THIN, // WEIGHT_THIN
2614             ::css::awt::FontWeight::ULTRALIGHT, // WEIGHT_ULTRALIGHT
2615             ::css::awt::FontWeight::LIGHT, // WEIGHT_LIGHT
2616             ::css::awt::FontWeight::SEMILIGHT, // WEIGHT_SEMILIGHT
2617             ::css::awt::FontWeight::NORMAL, // WEIGHT_NORMAL
2618             ::css::awt::FontWeight::NORMAL, // WEIGHT_MEDIUM
2619             ::css::awt::FontWeight::SEMIBOLD, // WEIGHT_SEMIBOLD
2620             ::css::awt::FontWeight::BOLD, // WEIGHT_BOLD
2621             ::css::awt::FontWeight::ULTRABOLD, // WEIGHT_ULTRABOLD
2622             ::css::awt::FontWeight::BLACK }; // WEIGHT_BLACK
2623     return ::css::uno::makeAny(aWeight[nWeight]);
2624 }
2625 
2626 // static
2627 ::FontWeight Document::mapFontWeight(::css::uno::Any const & rWeight)
2628 {
2629     float nWeight = ::css::awt::FontWeight::NORMAL;
2630     rWeight >>= nWeight;
2631     return nWeight <= ::css::awt::FontWeight::DONTKNOW ? WEIGHT_DONTKNOW
2632         : nWeight <= ::css::awt::FontWeight::THIN ? WEIGHT_THIN
2633         : nWeight <= ::css::awt::FontWeight::ULTRALIGHT ? WEIGHT_ULTRALIGHT
2634         : nWeight <= ::css::awt::FontWeight::LIGHT ? WEIGHT_LIGHT
2635         : nWeight <= ::css::awt::FontWeight::SEMILIGHT ? WEIGHT_SEMILIGHT
2636         : nWeight <= ::css::awt::FontWeight::NORMAL ? WEIGHT_NORMAL
2637         : nWeight <= ::css::awt::FontWeight::SEMIBOLD ? WEIGHT_SEMIBOLD
2638         : nWeight <= ::css::awt::FontWeight::BOLD ? WEIGHT_BOLD
2639         : nWeight <= ::css::awt::FontWeight::ULTRABOLD ? WEIGHT_ULTRABOLD
2640         : WEIGHT_BLACK;
2641 }
2642 
2643 }
2644 
2645