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 		// Sym2_6109,
1051 		//aAttribs[i].Value = mapFontColor( aFont.GetColor() );
1052 		aAttribs[i].Value = mapFontColor( m_rEngine.GetTextColor() );
1053 		aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE;
1054 		i++;
1055 	}
1056 	//character font name
1057 	{
1058 		aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharFontName"));
1059 		aAttribs[i].Handle = -1;
1060 		aAttribs[i].Value = ::css::uno::makeAny( (::rtl::OUString)aFont.GetName() );
1061 		aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE;
1062 		i++;
1063 	}
1064 	//character height
1065 	{
1066 		aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharHeight"));
1067 		aAttribs[i].Handle = -1;
1068 		aAttribs[i].Value = ::css::uno::makeAny( (sal_Int16)aFont.GetHeight() );
1069 		aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE;
1070 		i++;
1071 	}
1072 	//character posture
1073 	{
1074 		aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharPosture"));
1075 		aAttribs[i].Handle = -1;
1076 		aAttribs[i].Value = ::css::uno::makeAny( (sal_Int16)aFont.GetItalic() );
1077 		aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE;
1078 		i++;
1079 	}
1080 	//character relief
1081 	/*{
1082 		aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharRelief"));
1083 		aAttribs[i].Handle = -1;
1084 		aAttribs[i].Value = ::css::uno::makeAny( (sal_Int16)aFont.GetRelief() );
1085 		aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE;
1086 		i++;
1087 	}*/
1088 	//character strikeout
1089 	{
1090 		aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharStrikeout"));
1091 		aAttribs[i].Handle = -1;
1092 		aAttribs[i].Value = ::css::uno::makeAny( (sal_Int16)aFont.GetStrikeout() );
1093 		aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE;
1094 		i++;
1095 	}
1096 	//character underline
1097 	{
1098 		aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharUnderline"));
1099 		aAttribs[i].Handle = -1;
1100 		aAttribs[i].Value = ::css::uno::makeAny( (sal_Int16)aFont.GetUnderline() );
1101 		aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE;
1102 		i++;
1103 	}
1104 	//character weight
1105 	{
1106 		aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharWeight"));
1107 		aAttribs[i].Handle = -1;
1108 		aAttribs[i].Value = ::css::uno::makeAny( (float)aFont.GetWeight() );
1109 		aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE;
1110 		i++;
1111 	}
1112 	//character alignment
1113 	{
1114 		aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ParaAdjust"));
1115 		aAttribs[i].Handle = -1;
1116 		aAttribs[i].Value = ::css::uno::makeAny( (sal_Int16)m_rEngine.GetTextAlign() );
1117 		aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE;
1118 		i++;
1119 	}
1120     ::osl::MutexGuard aInternalGuard(GetMutex());
1121     ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber());
1122         // XXX  numeric overflow
1123 	// nIndex can be equal to Len();
1124     //if (nIndex < 0 || nIndex >= m_rEngine.GetText(nNumber).Len())
1125 	if (nIndex < 0 || nIndex > m_rEngine.GetText(nNumber).Len())
1126         throw ::css::lang::IndexOutOfBoundsException(
1127             ::rtl::OUString(
1128                 RTL_CONSTASCII_USTRINGPARAM(
1129                     "textwindowaccessibility.cxx:"
1130                     " Document::retrieveCharacterAttributes")),
1131             static_cast< ::css::uno::XWeak * >(this));
1132 
1133     // retrieve default attributes
1134     tPropValMap aCharAttrSeq;
1135     retrieveDefaultAttributesImpl( pParagraph, aRequestedAttributes, aCharAttrSeq );
1136 
1137     // retrieve run attributes
1138     tPropValMap aRunAttrSeq;
1139     retrieveRunAttributesImpl( pParagraph, nIndex, aRequestedAttributes, aRunAttrSeq );
1140 
1141     // merge default and run attributes
1142     for ( tPropValMap::const_iterator aRunIter  = aRunAttrSeq.begin();
1143           aRunIter != aRunAttrSeq.end();
1144           ++aRunIter )
1145     {
1146         aCharAttrSeq[ aRunIter->first ] = aRunIter->second;
1147     }
1148 
1149 	::css::beans::PropertyValue* pValues = aAttribs.getArray();
1150 	for (i = 0; i < AttributeCount; i++,pValues++)
1151 	{
1152 		aCharAttrSeq[ pValues->Name ] = *pValues;
1153 	}
1154 
1155     ::css::uno::Sequence< ::css::beans::PropertyValue > aRes = convertHashMapToSequence( aCharAttrSeq );
1156 
1157 	// Sym2_6109, sort the attributes
1158 	sal_Int32 nLength = aRes.getLength();
1159 	const ::css::beans::PropertyValue* pPairs = aRes.getConstArray();
1160 	sal_Int32* pIndices = new sal_Int32[nLength];
1161 	for( i = 0; i < nLength; i++ )
1162 		pIndices[i] = i;
1163 	std::sort( &pIndices[0], &pIndices[nLength], IndexCompare(pPairs) );
1164 	// create sorted sequences accoring to index array
1165 	::css::uno::Sequence< ::css::beans::PropertyValue > aNewValues( nLength );
1166 	::css::beans::PropertyValue* pNewValues = aNewValues.getArray();
1167 	for( i = 0; i < nLength; i++ )
1168 	{
1169 		pNewValues[i] = pPairs[pIndices[i]];
1170 	}
1171 	delete[] pIndices;
1172 
1173 	return aNewValues;
1174 }
1175 
1176 void Document::retrieveDefaultAttributesImpl(
1177     ParagraphImpl const * pParagraph,
1178     const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes,
1179     tPropValMap& rDefAttrSeq)
1180 {
1181     // default attributes are not supported by text engine
1182     (void) pParagraph;
1183     (void) RequestedAttributes;
1184     (void) rDefAttrSeq;
1185 }
1186 
1187 ::css::uno::Sequence< ::css::beans::PropertyValue >
1188 Document::retrieveDefaultAttributes(
1189     ParagraphImpl const * pParagraph,
1190     const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes)
1191 {
1192     ::osl::Guard< ::comphelper::IMutex > aExternalGuard( getExternalLock() );
1193     ::osl::MutexGuard aInternalGuard( GetMutex() );
1194 
1195     tPropValMap aDefAttrSeq;
1196     retrieveDefaultAttributesImpl( pParagraph, RequestedAttributes, aDefAttrSeq );
1197     return convertHashMapToSequence( aDefAttrSeq );
1198 }
1199 
1200 // static
1201 ::css::uno::Sequence< ::css::beans::PropertyValue >
1202 Document::convertHashMapToSequence(tPropValMap& rAttrSeq)
1203 {
1204     ::css::uno::Sequence< ::css::beans::PropertyValue > aValues( rAttrSeq.size() );
1205     ::css::beans::PropertyValue* pValues = aValues.getArray();
1206     ::sal_Int32 i = 0;
1207     for ( tPropValMap::const_iterator aIter  = rAttrSeq.begin();
1208           aIter != rAttrSeq.end();
1209           ++aIter )
1210     {
1211         pValues[i] = aIter->second;
1212         ++i;
1213     }
1214     return aValues;
1215 }
1216 
1217 void Document::retrieveRunAttributesImpl(
1218     ParagraphImpl const * pParagraph, ::sal_Int32 Index,
1219     const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes,
1220     tPropValMap& rRunAttrSeq)
1221 {
1222     ::sal_uLong nNumber = static_cast< ::sal_uLong >( pParagraph->getNumber() );
1223     ::TextPaM aPaM( nNumber, static_cast< ::sal_uInt16 >( Index ) );
1224         // XXX  numeric overflow
1225     // FIXME  TEXTATTR_HYPERLINK ignored:
1226     ::TextAttribFontColor const * pColor
1227           = static_cast< ::TextAttribFontColor const * >(
1228               m_rEngine.FindAttrib( aPaM, TEXTATTR_FONTCOLOR ) );
1229     ::TextAttribFontWeight const * pWeight
1230           = static_cast< ::TextAttribFontWeight const * >(
1231               m_rEngine.FindAttrib( aPaM, TEXTATTR_FONTWEIGHT ) );
1232     tPropValMap aRunAttrSeq;
1233     if ( pColor )
1234     {
1235         ::css::beans::PropertyValue aPropVal;
1236         aPropVal.Name =
1237             ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CharColor" ) );
1238         aPropVal.Handle = -1;
1239         aPropVal.Value = mapFontColor( pColor->GetColor() );
1240         aPropVal.State = ::css::beans::PropertyState_DIRECT_VALUE;
1241         aRunAttrSeq[ aPropVal.Name ] = aPropVal;
1242     }
1243     if ( pWeight )
1244     {
1245         ::css::beans::PropertyValue aPropVal;
1246         aPropVal.Name =
1247             ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CharWeight" ) );
1248         aPropVal.Handle = -1;
1249         aPropVal.Value = mapFontWeight( pWeight->getFontWeight() );
1250         aPropVal.State = ::css::beans::PropertyState_DIRECT_VALUE;
1251         aRunAttrSeq[ aPropVal.Name ] = aPropVal;
1252     }
1253     if ( RequestedAttributes.getLength() == 0 )
1254     {
1255         rRunAttrSeq = aRunAttrSeq;
1256     }
1257     else
1258     {
1259         const ::rtl::OUString* pReqAttrs = RequestedAttributes.getConstArray();
1260         const ::sal_Int32 nLength = RequestedAttributes.getLength();
1261         for ( ::sal_Int32 i = 0; i < nLength; ++i )
1262         {
1263             tPropValMap::iterator aIter = aRunAttrSeq.find( pReqAttrs[i] );
1264             if ( aIter != aRunAttrSeq.end() )
1265             {
1266                 rRunAttrSeq[ (*aIter).first ] = (*aIter).second;
1267             }
1268         }
1269     }
1270 }
1271 
1272 ::css::uno::Sequence< ::css::beans::PropertyValue >
1273 Document::retrieveRunAttributes(
1274     ParagraphImpl const * pParagraph, ::sal_Int32 Index,
1275     const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes)
1276 {
1277     ::osl::Guard< ::comphelper::IMutex > aExternalGuard( getExternalLock() );
1278     ::osl::MutexGuard aInternalGuard( GetMutex() );
1279     ::sal_uLong nNumber = static_cast< ::sal_uLong >( pParagraph->getNumber() );
1280         // XXX  numeric overflow
1281     if ( Index < 0 || Index >= m_rEngine.GetText(nNumber).Len() )
1282         throw ::css::lang::IndexOutOfBoundsException(
1283             ::rtl::OUString(
1284                 RTL_CONSTASCII_USTRINGPARAM(
1285                     "textwindowaccessibility.cxx:"
1286                     " Document::retrieveRunAttributes") ),
1287             static_cast< ::css::uno::XWeak * >( this ) );
1288 
1289     tPropValMap aRunAttrSeq;
1290     retrieveRunAttributesImpl( pParagraph, Index, RequestedAttributes, aRunAttrSeq );
1291     return convertHashMapToSequence( aRunAttrSeq );
1292 }
1293 
1294 void Document::changeParagraphText(ParagraphImpl * pParagraph,
1295                                    ::rtl::OUString const & rText)
1296 {
1297     ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1298     {
1299         ::osl::MutexGuard aInternalGuard(GetMutex());
1300         ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber());
1301             // XXX  numeric overflow
1302         changeParagraphText(nNumber, 0, m_rEngine.GetTextLen(nNumber), false,
1303                             false, rText);
1304     }
1305 }
1306 
1307 void Document::changeParagraphText(ParagraphImpl * pParagraph,
1308                                    ::sal_Int32 nBegin, ::sal_Int32 nEnd,
1309                                    bool bCut, bool bPaste,
1310                                    ::rtl::OUString const & rText)
1311 {
1312     ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1313     {
1314         ::osl::MutexGuard aInternalGuard(GetMutex());
1315         ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber());
1316             // XXX  numeric overflow
1317         if (nBegin < 0 || nBegin > nEnd
1318             || nEnd > m_rEngine.GetText(nNumber).Len())
1319             throw ::css::lang::IndexOutOfBoundsException(
1320                 ::rtl::OUString(
1321                     RTL_CONSTASCII_USTRINGPARAM(
1322                         "textwindowaccessibility.cxx:"
1323                         " Document::changeParagraphText")),
1324                 static_cast< ::css::uno::XWeak * >(this));
1325         changeParagraphText(nNumber, static_cast< ::sal_uInt16 >(nBegin),
1326                             static_cast< ::sal_uInt16 >(nEnd), bCut, bPaste, rText);
1327             // XXX  numeric overflow (2x)
1328     }
1329 }
1330 
1331 void Document::copyParagraphText(ParagraphImpl const * pParagraph,
1332                                  ::sal_Int32 nBegin, ::sal_Int32 nEnd)
1333 {
1334     ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1335     {
1336         ::osl::MutexGuard aInternalGuard(GetMutex());
1337         ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber());
1338             // XXX  numeric overflow
1339         if (nBegin < 0 || nBegin > nEnd
1340             || nEnd > m_rEngine.GetText(nNumber).Len())
1341             throw ::css::lang::IndexOutOfBoundsException(
1342                 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
1343                                     "textwindowaccessibility.cxx:"
1344                                     " Document::copyParagraphText")),
1345                 static_cast< ::css::uno::XWeak * >(this));
1346         m_rView.SetSelection(
1347             ::TextSelection(::TextPaM(nNumber, static_cast< ::sal_uInt16 >(nBegin)),
1348                             ::TextPaM(nNumber, static_cast< ::sal_uInt16 >(nEnd))));
1349             // XXX  numeric overflow (2x)
1350         m_rView.Copy();
1351     }
1352 }
1353 
1354 void Document::changeParagraphAttributes(
1355     ParagraphImpl * pParagraph, ::sal_Int32 nBegin, ::sal_Int32 nEnd,
1356     ::css::uno::Sequence< ::css::beans::PropertyValue > const & rAttributeSet)
1357 {
1358     ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1359     {
1360         ::osl::MutexGuard aInternalGuard(GetMutex());
1361         ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber());
1362         // XXX  numeric overflow
1363         if (nBegin < 0 || nBegin > nEnd
1364             || nEnd > m_rEngine.GetText(nNumber).Len())
1365             throw ::css::lang::IndexOutOfBoundsException(
1366                 ::rtl::OUString(
1367                     RTL_CONSTASCII_USTRINGPARAM(
1368                         "textwindowaccessibility.cxx:"
1369                         " Document::changeParagraphAttributes")),
1370                 static_cast< ::css::uno::XWeak * >(this));
1371 
1372         // FIXME  The new attributes are added to any attributes already set,
1373         // they do not replace the old attributes as required by
1374         // XAccessibleEditableText.setAttributes:
1375         for (::sal_Int32 i = 0; i < rAttributeSet.getLength(); ++i)
1376             if (rAttributeSet[i].Name.equalsAsciiL(
1377                     RTL_CONSTASCII_STRINGPARAM("CharColor")))
1378                 m_rEngine.SetAttrib(::TextAttribFontColor(
1379                                         mapFontColor(rAttributeSet[i].Value)),
1380                                     nNumber, static_cast< ::sal_uInt16 >(nBegin),
1381                                     static_cast< ::sal_uInt16 >(nEnd));
1382                     // XXX  numeric overflow (2x)
1383             else if (rAttributeSet[i].Name.equalsAsciiL(
1384                          RTL_CONSTASCII_STRINGPARAM("CharWeight")))
1385                 m_rEngine.SetAttrib(::TextAttribFontWeight(
1386                                         mapFontWeight(rAttributeSet[i].Value)),
1387                                     nNumber, static_cast< ::sal_uInt16 >(nBegin),
1388                                     static_cast< ::sal_uInt16 >(nEnd));
1389                     // XXX  numeric overflow (2x)
1390     }
1391 }
1392 
1393 void Document::changeParagraphSelection(ParagraphImpl * pParagraph,
1394                                         ::sal_Int32 nBegin, ::sal_Int32 nEnd)
1395 {
1396     ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1397     {
1398         ::osl::MutexGuard aInternalGuard(GetMutex());
1399         ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber());
1400             // XXX  numeric overflow
1401         if (nBegin < 0 || nBegin > nEnd
1402             || nEnd > m_rEngine.GetText(nNumber).Len())
1403             throw ::css::lang::IndexOutOfBoundsException(
1404                 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
1405                                     "textwindowaccessibility.cxx:"
1406                                     " Document::changeParagraphSelection")),
1407                 static_cast< ::css::uno::XWeak * >(this));
1408         m_rView.SetSelection(
1409             ::TextSelection(::TextPaM(nNumber, static_cast< ::sal_uInt16 >(nBegin)),
1410                             ::TextPaM(nNumber, static_cast< ::sal_uInt16 >(nEnd))));
1411             // XXX  numeric overflow (2x)
1412     }
1413 }
1414 
1415 ::css::i18n::Boundary
1416 Document::retrieveParagraphLineBoundary( ParagraphImpl const * pParagraph,
1417                                          ::sal_Int32 nIndex, ::sal_Int32 *pLineNo )
1418 {
1419     ::css::i18n::Boundary aBoundary;
1420     aBoundary.startPos = nIndex;
1421     aBoundary.endPos = nIndex;
1422 
1423     ::osl::Guard< ::comphelper::IMutex > aExternalGuard( getExternalLock() );
1424     {
1425         ::osl::MutexGuard aInternalGuard( GetMutex() );
1426         ::sal_uLong nNumber = static_cast< ::sal_uLong >( pParagraph->getNumber() );
1427         if ( nIndex < 0 || nIndex > m_rEngine.GetText( nNumber ).Len() )
1428             throw ::css::lang::IndexOutOfBoundsException(
1429                 ::rtl::OUString(
1430                     RTL_CONSTASCII_USTRINGPARAM(
1431                         "textwindowaccessibility.cxx:"
1432                         " Document::retrieveParagraphLineBoundary" ) ),
1433                 static_cast< ::css::uno::XWeak * >( this ) );
1434         ::sal_Int32 nLineStart = 0;
1435         ::sal_Int32 nLineEnd = 0;
1436         ::sal_uInt16 nLineCount = m_rEngine.GetLineCount( nNumber );
1437         for ( ::sal_uInt16 nLine = 0; nLine < nLineCount; ++nLine )
1438         {
1439             ::sal_Int32 nLineLength = static_cast< ::sal_Int32 >(
1440                 m_rEngine.GetLineLen( nNumber, nLine ) );
1441             nLineStart = nLineEnd;
1442             nLineEnd += nLineLength;
1443             if ( nIndex >= nLineStart && ( ( nLine == nLineCount - 1 ) ? nIndex <= nLineEnd : nIndex < nLineEnd ) )
1444             {
1445                 aBoundary.startPos = nLineStart;
1446                 aBoundary.endPos = nLineEnd;
1447                 if( pLineNo )
1448                     pLineNo[0] = nLine;
1449                 break;
1450             }
1451         }
1452     }
1453 
1454     return aBoundary;
1455 }
1456 
1457 ::css::i18n::Boundary
1458 Document::retrieveParagraphBoundaryOfLine( ParagraphImpl const * pParagraph,
1459                                            ::sal_Int32 nLineNo )
1460 {
1461     ::css::i18n::Boundary aBoundary;
1462     aBoundary.startPos = 0;
1463     aBoundary.endPos = 0;
1464 
1465     ::osl::Guard< ::comphelper::IMutex > aExternalGuard( getExternalLock() );
1466     {
1467         ::osl::MutexGuard aInternalGuard( GetMutex() );
1468         ::sal_uLong nNumber = static_cast< ::sal_uLong >( pParagraph->getNumber() );
1469         if ( nLineNo >= m_rEngine.GetLineCount( nNumber ) )
1470             throw ::css::lang::IndexOutOfBoundsException(
1471                 ::rtl::OUString(
1472                     RTL_CONSTASCII_USTRINGPARAM(
1473                         "textwindowaccessibility.cxx:"
1474                         " Document::retrieveParagraphBoundaryOfLine" ) ),
1475                 static_cast< ::css::uno::XWeak * >( this ) );
1476         ::sal_Int32 nLineStart = 0;
1477         ::sal_Int32 nLineEnd = 0;
1478         for ( ::sal_uInt16 nLine = 0; nLine <= nLineNo; ++nLine )
1479         {
1480             ::sal_Int32 nLineLength = static_cast< ::sal_Int32 >(
1481                 m_rEngine.GetLineLen( nNumber, nLine ) );
1482             nLineStart = nLineEnd;
1483             nLineEnd += nLineLength;
1484         }
1485 
1486         aBoundary.startPos = nLineStart;
1487         aBoundary.endPos = nLineEnd;
1488     }
1489 
1490     return aBoundary;
1491 }
1492 
1493 sal_Int32 Document::retrieveParagraphLineWithCursor( ParagraphImpl const * pParagraph )
1494 {
1495     ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1496     ::osl::MutexGuard aInternalGuard(GetMutex());
1497     ::TextSelection const & rSelection = m_rView.GetSelection();
1498     Paragraphs::size_type nNumber = pParagraph->getNumber();
1499     TextPaM aEndPaM( rSelection.GetEnd() );
1500 
1501     return aEndPaM.GetPara() == nNumber
1502         ? m_rView.GetLineNumberOfCursorInSelection() : -1;
1503 }
1504 
1505 
1506 ::css::uno::Reference< ::css::accessibility::XAccessibleRelationSet >
1507 Document::retrieveParagraphRelationSet( ParagraphImpl const * pParagraph )
1508 {
1509     ::osl::MutexGuard aInternalGuard( GetMutex() );
1510 
1511     ::utl::AccessibleRelationSetHelper* pRelationSetHelper = new ::utl::AccessibleRelationSetHelper();
1512     ::css::uno::Reference< ::css::accessibility::XAccessibleRelationSet > xSet = pRelationSetHelper;
1513 
1514     Paragraphs::iterator aPara( m_xParagraphs->begin() + pParagraph->getNumber() );
1515 
1516     if ( aPara > m_aVisibleBegin && aPara < m_aVisibleEnd )
1517     {
1518         ::css::uno::Sequence< ::css::uno::Reference< ::css::uno::XInterface > > aSequence(1);
1519         aSequence[0] = getAccessibleChild( aPara - 1 );
1520         ::css::accessibility::AccessibleRelation aRelation( ::css::accessibility::AccessibleRelationType::CONTENT_FLOWS_FROM, aSequence );
1521         pRelationSetHelper->AddRelation( aRelation );
1522     }
1523 
1524     if ( aPara >= m_aVisibleBegin && aPara < m_aVisibleEnd -1 )
1525     {
1526         ::css::uno::Sequence< ::css::uno::Reference< ::css::uno::XInterface > > aSequence(1);
1527         aSequence[0] = getAccessibleChild( aPara + 1 );
1528         ::css::accessibility::AccessibleRelation aRelation( ::css::accessibility::AccessibleRelationType::CONTENT_FLOWS_TO, aSequence );
1529         pRelationSetHelper->AddRelation( aRelation );
1530     }
1531 
1532     return xSet;
1533 }
1534 
1535 void Document::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent )
1536 {
1537 	switch ( rVclWindowEvent.GetId() )
1538 	{
1539 		case VCLEVENT_WINDOW_GETFOCUS:
1540 		case VCLEVENT_WINDOW_LOSEFOCUS:
1541 		{
1542 			// #107179# if our parent is a compound control (e.g. MultiLineEdit),
1543 			// suppress the window focus events here
1544 // IAccessible2 implementation 2009
1545 			//if ( !m_bCompoundControlChild )
1546 				VCLXAccessibleComponent::ProcessWindowEvent( rVclWindowEvent );
1547 		}
1548 		break;
1549 		default:
1550 			VCLXAccessibleComponent::ProcessWindowEvent( rVclWindowEvent );
1551 	}
1552 }
1553 
1554 // virtual
1555 ::sal_Int32 SAL_CALL Document::getAccessibleChildCount()
1556     throw (::css::uno::RuntimeException)
1557 {
1558     ::comphelper::OExternalLockGuard aGuard(this);
1559     init();
1560     return m_aVisibleEnd - m_aVisibleBegin;
1561 }
1562 
1563 // virtual
1564 ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL
1565 Document::getAccessibleChild(::sal_Int32 i)
1566     throw (::css::lang::IndexOutOfBoundsException,
1567            ::css::uno::RuntimeException)
1568 {
1569     ::comphelper::OExternalLockGuard aGuard(this);
1570     init();
1571     if (i < 0 || i >= m_aVisibleEnd - m_aVisibleBegin)
1572         throw ::css::lang::IndexOutOfBoundsException(
1573             ::rtl::OUString(
1574                 RTL_CONSTASCII_USTRINGPARAM(
1575                     "textwindowaccessibility.cxx:"
1576                     " Document::getAccessibleChild")),
1577             static_cast< ::css::uno::XWeak * >(this));
1578     return getAccessibleChild(m_aVisibleBegin
1579                               + static_cast< Paragraphs::size_type >(i));
1580 }
1581 
1582 // virtual
1583 ::sal_Int16 SAL_CALL Document::getAccessibleRole()
1584     throw (::css::uno::RuntimeException)
1585 {
1586     return ::css::accessibility::AccessibleRole::TEXT_FRAME;
1587 }
1588 
1589 // virtual
1590 ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL
1591 Document::getAccessibleAtPoint(::css::awt::Point const & rPoint)
1592     throw (::css::uno::RuntimeException)
1593 {
1594     ::comphelper::OExternalLockGuard aGuard(this);
1595     init();
1596     if (rPoint.X >= 0
1597         && rPoint.X < m_rView.GetWindow()->GetOutputSizePixel().Width()
1598         && rPoint.Y >= 0 && rPoint.Y < m_nViewHeight)
1599     {
1600         ::sal_Int32 nOffset = m_nViewOffset + rPoint.Y; // XXX  numeric overflow
1601         ::sal_Int32 nPos = m_nViewOffset - m_nVisibleBeginOffset;
1602         for (Paragraphs::iterator aIt(m_aVisibleBegin); aIt != m_aVisibleEnd;
1603              ++aIt)
1604         {
1605             nPos += aIt->getHeight(); // XXX  numeric overflow
1606             if (nOffset < nPos)
1607                 return getAccessibleChild(aIt);
1608         }
1609     }
1610     return 0;
1611 }
1612 void Document::FillAccessibleStateSet( utl::AccessibleStateSetHelper& rStateSet )
1613 {
1614 	VCLXAccessibleComponent::FillAccessibleStateSet( rStateSet );
1615 	if (!m_rView.IsReadOnly())
1616 		rStateSet.AddState( ::css::accessibility::AccessibleStateType::EDITABLE );
1617 }
1618 
1619 void	Document::FillAccessibleRelationSet( utl::AccessibleRelationSetHelper& rRelationSet )
1620 {
1621 	if( getAccessibleParent()->getAccessibleContext()->getAccessibleRole() == ::css::accessibility::AccessibleRole::SCROLL_PANE )
1622 	{
1623 		::css::uno::Sequence< ::css::uno::Reference< ::css::uno::XInterface > > aSequence(1);
1624 		aSequence[0] = getAccessibleParent();
1625 		rRelationSet.AddRelation( ::css::accessibility::AccessibleRelation( ::css::accessibility::AccessibleRelationType::MEMBER_OF, aSequence ) );
1626 	}
1627 	else
1628 	{
1629 		 VCLXAccessibleComponent::FillAccessibleRelationSet(rRelationSet);
1630 	}
1631 }
1632 // virtual
1633 void SAL_CALL Document::disposing()
1634 {
1635     m_aEngineListener.endListening();
1636     m_aViewListener.endListening();
1637     if (m_xParagraphs.get() != 0)
1638         disposeParagraphs();
1639     VCLXAccessibleComponent::disposing();
1640 }
1641 
1642 // virtual
1643 void Document::Notify(::SfxBroadcaster &, ::SfxHint const & rHint)
1644 {
1645     if (rHint.ISA(::TextHint))
1646     {
1647         ::TextHint const & rTextHint
1648               = static_cast< ::TextHint const & >(rHint);
1649         switch (rTextHint.GetId())
1650         {
1651         case TEXT_HINT_PARAINSERTED:
1652         case TEXT_HINT_PARAREMOVED:
1653             // TEXT_HINT_PARAINSERTED and TEXT_HINT_PARAREMOVED are sent at
1654             // "unsafe" times (when the text engine has not yet re-formatted its
1655             // content), so that for example calling ::TextEngine::GetTextHeight
1656             // from within the code that handles TEXT_HINT_PARAINSERTED causes
1657             // trouble within the text engine.  Therefore, these hints are just
1658             // buffered until a following ::TextEngine::FormatDoc causes a
1659             // TEXT_HINT_TEXTFORMATTED to come in:
1660         case TEXT_HINT_FORMATPARA:
1661             // ::TextEngine::FormatDoc sends a sequence of
1662             // TEXT_HINT_FORMATPARAs, followed by an optional
1663             // TEXT_HINT_TEXTHEIGHTCHANGED, followed in all cases by one
1664             // TEXT_HINT_TEXTFORMATTED.  Only the TEXT_HINT_FORMATPARAs contain
1665             // the the numbers of the affected paragraphs, but they are sent
1666             // before the changes are applied.  Therefore, TEXT_HINT_FORMATPARAs
1667             // are just buffered until another hint comes in:
1668             {
1669                 ::osl::MutexGuard aInternalGuard(GetMutex());
1670                 if (!isAlive())
1671                     break;
1672 
1673                 m_aParagraphNotifications.push(rTextHint);
1674                 break;
1675             }
1676         case TEXT_HINT_TEXTFORMATTED:
1677         case TEXT_HINT_TEXTHEIGHTCHANGED:
1678         case TEXT_HINT_MODIFIED:
1679             {
1680                 ::osl::MutexGuard aInternalGuard(GetMutex());
1681                 if (!isAlive())
1682                     break;
1683                 handleParagraphNotifications();
1684                 break;
1685             }
1686         case TEXT_HINT_VIEWSCROLLED:
1687             {
1688                 ::osl::MutexGuard aInternalGuard(GetMutex());
1689                 if (!isAlive())
1690                     break;
1691                 handleParagraphNotifications();
1692 
1693                 ::sal_Int32 nOffset = static_cast< ::sal_Int32 >(
1694                     m_rView.GetStartDocPos().Y());
1695                     // XXX  numeric overflow
1696                 if (nOffset != m_nViewOffset)
1697                 {
1698                     m_nViewOffset = nOffset;
1699 
1700                     Paragraphs::iterator aOldVisibleBegin(
1701                         m_aVisibleBegin);
1702                     Paragraphs::iterator aOldVisibleEnd(m_aVisibleEnd);
1703 
1704                     determineVisibleRange();
1705 
1706                     notifyVisibleRangeChanges(aOldVisibleBegin,
1707                                                 aOldVisibleEnd,
1708                                                 m_xParagraphs->end());
1709                 }
1710                 break;
1711             }
1712         case TEXT_HINT_VIEWSELECTIONCHANGED:
1713             {
1714                 ::osl::MutexGuard aInternalGuard(GetMutex());
1715                 if (!isAlive())
1716                     break;
1717 
1718                 if (m_aParagraphNotifications.empty())
1719                 {
1720                     handleSelectionChangeNotification();
1721                 }
1722                 else
1723                 {
1724                     // TEXT_HINT_VIEWSELECTIONCHANGED is sometimes sent at
1725                     // "unsafe" times (when the text engine has not yet re-
1726                     // formatted its content), so that for example calling
1727                     // ::TextEngine::GetTextHeight from within the code that
1728                     // handles a previous TEXT_HINT_PARAINSERTED causes
1729                     // trouble within the text engine.  Therefore, these
1730                     // hints are just buffered (along with
1731                     // TEXT_HINT_PARAINSERTED/REMOVED/FORMATPARA) until a
1732                     // following ::TextEngine::FormatDoc causes a
1733                     // TEXT_HINT_TEXTFORMATTED to come in:
1734                     m_bSelectionChangedNotification = true;
1735                 }
1736                 break;
1737             }
1738         }
1739     }
1740 }
1741 
1742 IMPL_LINK(Document, WindowEventHandler, ::VclSimpleEvent *, pEvent)
1743 {
1744     switch (pEvent->GetId())
1745     {
1746     case VCLEVENT_WINDOW_RESIZE:
1747         {
1748             ::osl::MutexGuard aInternalGuard(GetMutex());
1749             if (!isAlive())
1750                 break;
1751 
1752             ::sal_Int32 nHeight = static_cast< ::sal_Int32 >(
1753                 m_rView.GetWindow()->GetOutputSizePixel().Height());
1754                 // XXX  numeric overflow
1755             if (nHeight != m_nViewHeight)
1756             {
1757                 m_nViewHeight = nHeight;
1758 
1759                 Paragraphs::iterator aOldVisibleBegin(m_aVisibleBegin);
1760                 Paragraphs::iterator aOldVisibleEnd(m_aVisibleEnd);
1761 
1762                 determineVisibleRange();
1763 
1764                 notifyVisibleRangeChanges(aOldVisibleBegin, aOldVisibleEnd,
1765                                             m_xParagraphs->end());
1766             }
1767             break;
1768         }
1769     case VCLEVENT_WINDOW_GETFOCUS:
1770         {
1771             ::osl::MutexGuard aInternalGuard(GetMutex());
1772             if (!isAlive())
1773                 break;
1774 			//to enable the PARAGRAPH to get focus for multiline edit
1775 			::sal_Int32 count = getAccessibleChildCount();
1776 			::sal_Bool bEmpty = m_aFocused == m_aVisibleEnd && count == 1;
1777             if ((m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd) || bEmpty)
1778             {
1779 				Paragraphs::iterator m_aTemp = bEmpty ? m_aVisibleBegin : m_aFocused;
1780                 ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(m_aTemp));
1781 				if (xParagraph.is())
1782 				{
1783 					xParagraph->notifyEvent(
1784 						::css::accessibility::AccessibleEventId::
1785 						STATE_CHANGED,
1786 						::css::uno::Any(),
1787 						::css::uno::makeAny(
1788 							::css::accessibility::AccessibleStateType::
1789 							FOCUSED));
1790 				}
1791             }
1792 			/*
1793                 ::rtl::Reference< ParagraphImpl > xParagraph(
1794                     getParagraph(m_aFocused));
1795                 if (xParagraph.is())
1796                     xParagraph->notifyEvent(
1797                         ::css::accessibility::AccessibleEventId::
1798                         STATE_CHANGED,
1799                         ::css::uno::Any(),
1800                         ::css::uno::makeAny(
1801                             ::css::accessibility::AccessibleStateType::
1802                             FOCUSED));
1803 			*/
1804             break;
1805         }
1806     case VCLEVENT_WINDOW_LOSEFOCUS:
1807         {
1808             ::osl::MutexGuard aInternalGuard(GetMutex());
1809             if (!isAlive())
1810                 break;
1811 			//to enable the PARAGRAPH to get focus for multiline edit
1812 			::sal_Int32 count = getAccessibleChildCount();
1813 			::sal_Bool bEmpty = m_aFocused == m_aVisibleEnd && count == 1;
1814             if ((m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd) || bEmpty)
1815             {
1816 				Paragraphs::iterator m_aTemp = bEmpty ? m_aVisibleBegin : m_aFocused;
1817                 ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(m_aTemp));
1818                 if (xParagraph.is())
1819                     xParagraph->notifyEvent(
1820                         ::css::accessibility::AccessibleEventId::
1821                         STATE_CHANGED,
1822                         ::css::uno::makeAny(
1823                             ::css::accessibility::AccessibleStateType::
1824                             FOCUSED),
1825                         ::css::uno::Any());
1826             }
1827 
1828 			/*
1829             if (m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd)
1830             {
1831                 ::rtl::Reference< ParagraphImpl > xParagraph(
1832                     getParagraph(m_aFocused));
1833                 if (xParagraph.is())
1834                     xParagraph->notifyEvent(
1835                         ::css::accessibility::AccessibleEventId::
1836                         STATE_CHANGED,
1837                         ::css::uno::makeAny(
1838                             ::css::accessibility::AccessibleStateType::
1839                             FOCUSED),
1840                         ::css::uno::Any());
1841             }
1842 			*/
1843             break;
1844         }
1845     }
1846     return 0;
1847 }
1848 
1849 void Document::init()
1850 {
1851     if (m_xParagraphs.get() == 0)
1852     {
1853         ::sal_uLong nCount = m_rEngine.GetParagraphCount();
1854         ::std::auto_ptr< Paragraphs > p(new Paragraphs);
1855         p->reserve(static_cast< Paragraphs::size_type >(nCount));
1856             // numeric overflow is harmless here
1857         for (::sal_uLong i = 0; i < nCount; ++i)
1858             p->push_back(ParagraphInfo(static_cast< ::sal_Int32 >(
1859                                            m_rEngine.GetTextHeight(i))));
1860                 // XXX  numeric overflow
1861         m_nViewOffset = static_cast< ::sal_Int32 >(
1862             m_rView.GetStartDocPos().Y()); // XXX  numeric overflow
1863         m_nViewHeight = static_cast< ::sal_Int32 >(
1864             m_rView.GetWindow()->GetOutputSizePixel().Height());
1865             // XXX  numeric overflow
1866         m_xParagraphs = p;
1867         determineVisibleRange();
1868         m_nSelectionFirstPara = -1;
1869         m_nSelectionFirstPos = -1;
1870         m_nSelectionLastPara = -1;
1871         m_nSelectionLastPos = -1;
1872         m_aFocused = m_xParagraphs->end();
1873         m_bSelectionChangedNotification = false;
1874         m_aEngineListener.startListening(m_rEngine);
1875         m_aViewListener.startListening(*m_rView.GetWindow());
1876     }
1877 }
1878 
1879 ::rtl::Reference< ParagraphImpl >
1880 Document::getParagraph(Paragraphs::iterator const & rIt)
1881 {
1882     return static_cast< ParagraphImpl * >(
1883         ::css::uno::Reference< ::css::accessibility::XAccessible >(
1884             rIt->getParagraph()).get());
1885 }
1886 
1887 ::css::uno::Reference< ::css::accessibility::XAccessible >
1888 Document::getAccessibleChild(Paragraphs::iterator const & rIt)
1889 {
1890     ::css::uno::Reference< ::css::accessibility::XAccessible > xParagraph(
1891         rIt->getParagraph());
1892     if (!xParagraph.is())
1893     {
1894         xParagraph = new Paragraph(this, rIt - m_xParagraphs->begin());
1895         rIt->setParagraph(xParagraph);
1896     }
1897     return xParagraph;
1898 }
1899 
1900 void Document::determineVisibleRange()
1901 {
1902     m_aVisibleBegin = m_xParagraphs->end();
1903     m_aVisibleEnd = m_aVisibleBegin;
1904     ::sal_Int32 nPos = 0;
1905     for (Paragraphs::iterator aIt = m_xParagraphs->begin();;)
1906     {
1907         if (aIt == m_xParagraphs->end())
1908         {
1909             m_nVisibleBeginOffset = 0;
1910             break;
1911         }
1912         ::sal_Int32 nOldPos = nPos;
1913         nPos += aIt->getHeight(); // XXX  numeric overflow
1914         if (m_aVisibleBegin == m_xParagraphs->end() && nPos >= m_nViewOffset)
1915         {
1916             m_aVisibleBegin = aIt;
1917             m_nVisibleBeginOffset = m_nViewOffset - nOldPos;
1918         }
1919         ++aIt;
1920         if (m_aVisibleBegin != m_xParagraphs->end()
1921             && (aIt == m_xParagraphs->end()
1922                 || nPos >= m_nViewOffset + m_nViewHeight))
1923             // XXX  numeric overflow
1924         {
1925             m_aVisibleEnd = aIt;
1926             break;
1927         }
1928     }
1929 }
1930 
1931 void Document::notifyVisibleRangeChanges(
1932     Paragraphs::iterator const & rOldVisibleBegin,
1933     Paragraphs::iterator const & rOldVisibleEnd,
1934     Paragraphs::iterator const & rInserted)
1935 {
1936     // XXX  Replace this code that determines which paragraphs have changed from
1937     // invisible to visible or vice versa with a better algorithm.
1938     {for (Paragraphs::iterator aIt(rOldVisibleBegin); aIt != rOldVisibleEnd;
1939           ++aIt)
1940         if (aIt != rInserted
1941             && (aIt < m_aVisibleBegin || aIt >= m_aVisibleEnd))
1942             NotifyAccessibleEvent(
1943                 ::css::accessibility::AccessibleEventId::
1944                 CHILD,
1945                 ::css::uno::makeAny(getAccessibleChild(aIt)),
1946                 ::css::uno::Any());
1947     }
1948     {for (Paragraphs::iterator aIt(m_aVisibleBegin); aIt != m_aVisibleEnd;
1949           ++aIt)
1950         if (aIt == rInserted
1951             || aIt < rOldVisibleBegin || aIt >= rOldVisibleEnd)
1952             NotifyAccessibleEvent(
1953                 ::css::accessibility::AccessibleEventId::
1954                 CHILD,
1955                 ::css::uno::Any(),
1956                 ::css::uno::makeAny(getAccessibleChild(aIt)));
1957     }
1958 }
1959 
1960 void
1961 Document::changeParagraphText(::sal_uLong nNumber, ::sal_uInt16 nBegin, ::sal_uInt16 nEnd,
1962                               bool bCut, bool bPaste,
1963                               ::rtl::OUString const & rText)
1964 {
1965     m_rView.SetSelection(::TextSelection(::TextPaM(nNumber, nBegin),
1966                                          ::TextPaM(nNumber, nEnd)));
1967     if (bCut)
1968         m_rView.Cut();
1969     else if (nBegin != nEnd)
1970         m_rView.DeleteSelected();
1971     if (bPaste)
1972         m_rView.Paste();
1973     else if (rText.getLength() != 0)
1974         m_rView.InsertText(rText);
1975 }
1976 
1977 void Document::handleParagraphNotifications()
1978 {
1979     while (!m_aParagraphNotifications.empty())
1980     {
1981         ::TextHint aHint(m_aParagraphNotifications.front());
1982         m_aParagraphNotifications.pop();
1983         switch (aHint.GetId())
1984         {
1985         case TEXT_HINT_PARAINSERTED:
1986             {
1987                 ::sal_uLong n = aHint.GetValue();
1988                 OSL_ENSURE(n <= m_xParagraphs->size(),
1989                            "bad TEXT_HINT_PARAINSERTED event");
1990 
1991                 // Save the values of old iterators (the iterators themselves
1992                 // will get invalidated), and adjust the old values so that they
1993                 // reflect the insertion of the new paragraph:
1994                 Paragraphs::size_type nOldVisibleBegin
1995                     = m_aVisibleBegin - m_xParagraphs->begin();
1996                 Paragraphs::size_type nOldVisibleEnd
1997                     = m_aVisibleEnd - m_xParagraphs->begin();
1998                 Paragraphs::size_type nOldFocused
1999                     = m_aFocused - m_xParagraphs->begin();
2000                 if (n <= nOldVisibleBegin)
2001                     ++nOldVisibleBegin; // XXX  numeric overflow
2002                 if (n <= nOldVisibleEnd)
2003                     ++nOldVisibleEnd; // XXX  numeric overflow
2004                 if (n <= nOldFocused)
2005                     ++nOldFocused; // XXX  numeric overflow
2006                 if (sal::static_int_cast<sal_Int32>(n) <= m_nSelectionFirstPara)
2007                     ++m_nSelectionFirstPara; // XXX  numeric overflow
2008                 if (sal::static_int_cast<sal_Int32>(n) <= m_nSelectionLastPara)
2009                     ++m_nSelectionLastPara; // XXX  numeric overflow
2010 
2011                 Paragraphs::iterator aIns(
2012                     m_xParagraphs->insert(
2013                         m_xParagraphs->begin() + n,
2014                         ParagraphInfo(static_cast< ::sal_Int32 >(
2015                                           m_rEngine.GetTextHeight(n)))));
2016                     // XXX  numeric overflow (2x)
2017 
2018                 determineVisibleRange();
2019                 m_aFocused = m_xParagraphs->begin() + nOldFocused;
2020 
2021                 for (Paragraphs::iterator aIt(aIns);;)
2022                 {
2023                     ++aIt;
2024                     if (aIt == m_xParagraphs->end())
2025                         break;
2026                     ::rtl::Reference< ParagraphImpl > xParagraph(
2027                         getParagraph(aIt));
2028                     if (xParagraph.is())
2029                         xParagraph->numberChanged(true);
2030                 }
2031 
2032                 notifyVisibleRangeChanges(
2033                     m_xParagraphs->begin() + nOldVisibleBegin,
2034                     m_xParagraphs->begin() + nOldVisibleEnd, aIns);
2035                 break;
2036             }
2037         case TEXT_HINT_PARAREMOVED:
2038             {
2039                 ::sal_uLong n = aHint.GetValue();
2040                 if (n == TEXT_PARA_ALL)
2041                 {
2042                     {for (Paragraphs::iterator aIt(m_aVisibleBegin);
2043                           aIt != m_aVisibleEnd; ++aIt)
2044                         NotifyAccessibleEvent(
2045                             ::css::accessibility::AccessibleEventId::
2046                             CHILD,
2047                             ::css::uno::makeAny(getAccessibleChild(aIt)),
2048                             ::css::uno::Any());
2049                     }
2050                     disposeParagraphs();
2051                     m_xParagraphs->clear();
2052                     determineVisibleRange();
2053                     m_nSelectionFirstPara = -1;
2054                     m_nSelectionFirstPos = -1;
2055                     m_nSelectionLastPara = -1;
2056                     m_nSelectionLastPos = -1;
2057                     m_aFocused = m_xParagraphs->end();
2058                 }
2059                 else
2060                 {
2061                     OSL_ENSURE(n < m_xParagraphs->size(),
2062                                "Bad TEXT_HINT_PARAREMOVED event");
2063 
2064                     Paragraphs::iterator aIt(m_xParagraphs->begin() + n);
2065                         // numeric overflow cannot occur
2066 
2067                     // Save the values of old iterators (the iterators
2068                     // themselves will get invalidated), and adjust the old
2069                     // values so that they reflect the removal of the paragraph:
2070                     Paragraphs::size_type nOldVisibleBegin
2071                         = m_aVisibleBegin - m_xParagraphs->begin();
2072                     Paragraphs::size_type nOldVisibleEnd
2073                         = m_aVisibleEnd - m_xParagraphs->begin();
2074                     bool bWasVisible
2075                         = nOldVisibleBegin <= n && n < nOldVisibleEnd;
2076                     Paragraphs::size_type nOldFocused
2077                         = m_aFocused - m_xParagraphs->begin();
2078                     bool bWasFocused = aIt == m_aFocused;
2079                     if (n < nOldVisibleBegin)
2080                         --nOldVisibleBegin;
2081                     if (n < nOldVisibleEnd)
2082                         --nOldVisibleEnd;
2083                     if (n < nOldFocused)
2084                         --nOldFocused;
2085                     if (sal::static_int_cast<sal_Int32>(n) < m_nSelectionFirstPara)
2086                         --m_nSelectionFirstPara;
2087                     else if (sal::static_int_cast<sal_Int32>(n) == m_nSelectionFirstPara)
2088                     {
2089                         if (m_nSelectionFirstPara == m_nSelectionLastPara)
2090                         {
2091                             m_nSelectionFirstPara = -1;
2092                             m_nSelectionFirstPos = -1;
2093                             m_nSelectionLastPara = -1;
2094                             m_nSelectionLastPos = -1;
2095                         }
2096                         else
2097                         {
2098                             ++m_nSelectionFirstPara;
2099                             m_nSelectionFirstPos = 0;
2100                         }
2101                     }
2102                     if (sal::static_int_cast<sal_Int32>(n) < m_nSelectionLastPara)
2103                         --m_nSelectionLastPara;
2104                     else if (sal::static_int_cast<sal_Int32>(n) == m_nSelectionLastPara)
2105                     {
2106                         OSL_ENSURE(m_nSelectionFirstPara < m_nSelectionLastPara,
2107                                    "logic error");
2108                         --m_nSelectionLastPara;
2109                         m_nSelectionLastPos = 0x7FFFFFFF;
2110                     }
2111 
2112                     ::css::uno::Reference< ::css::accessibility::XAccessible >
2113                           xStrong;
2114                     if (bWasVisible)
2115                         xStrong = getAccessibleChild(aIt);
2116                     ::css::uno::WeakReference<
2117                           ::css::accessibility::XAccessible > xWeak(
2118                               aIt->getParagraph());
2119                     aIt = m_xParagraphs->erase(aIt);
2120 
2121                     determineVisibleRange();
2122                     m_aFocused = bWasFocused ? m_xParagraphs->end()
2123                         : m_xParagraphs->begin() + nOldFocused;
2124 
2125                     for (; aIt != m_xParagraphs->end(); ++aIt)
2126                     {
2127                         ::rtl::Reference< ParagraphImpl > xParagraph(
2128                             getParagraph(aIt));
2129                         if (xParagraph.is())
2130                             xParagraph->numberChanged(false);
2131                     }
2132 
2133                     if (bWasVisible)
2134                         NotifyAccessibleEvent(
2135                             ::css::accessibility::AccessibleEventId::
2136                             CHILD,
2137                             ::css::uno::makeAny(getAccessibleChild(aIt)),
2138                             ::css::uno::Any());
2139 
2140                     ::css::uno::Reference< ::css::lang::XComponent > xComponent(
2141                         xWeak.get(), ::css::uno::UNO_QUERY);
2142                     if (xComponent.is())
2143                         xComponent->dispose();
2144 
2145                     notifyVisibleRangeChanges(
2146                         m_xParagraphs->begin() + nOldVisibleBegin,
2147                         m_xParagraphs->begin() + nOldVisibleEnd,
2148                         m_xParagraphs->end());
2149                 }
2150                 break;
2151             }
2152         case TEXT_HINT_FORMATPARA:
2153             {
2154                 ::sal_uLong n = aHint.GetValue();
2155                 OSL_ENSURE(n < m_xParagraphs->size(),
2156                            "Bad TEXT_HINT_FORMATPARA event");
2157 
2158                 (*m_xParagraphs)[static_cast< Paragraphs::size_type >(n)].
2159                     changeHeight(static_cast< ::sal_Int32 >(
2160                                      m_rEngine.GetTextHeight(n)));
2161                     // XXX  numeric overflow
2162                 Paragraphs::iterator aOldVisibleBegin(m_aVisibleBegin);
2163                 Paragraphs::iterator aOldVisibleEnd(m_aVisibleEnd);
2164                 determineVisibleRange();
2165                 notifyVisibleRangeChanges(aOldVisibleBegin, aOldVisibleEnd,
2166                                           m_xParagraphs->end());
2167 
2168                 if (n < m_xParagraphs->size())
2169                 {
2170                     Paragraphs::iterator aIt(m_xParagraphs->begin() + n);
2171                     ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(aIt));
2172                     if (xParagraph.is())
2173                         xParagraph->textChanged();
2174                 }
2175                 break;
2176             }
2177         default:
2178             OSL_ENSURE(false, "bad buffered hint");
2179             break;
2180         }
2181     }
2182     if (m_bSelectionChangedNotification)
2183     {
2184         m_bSelectionChangedNotification = false;
2185         handleSelectionChangeNotification();
2186     }
2187 }
2188 
2189 ::sal_Int32 Document::getSelectionType(::sal_Int32 nNewFirstPara, ::sal_Int32 nNewFirstPos, ::sal_Int32 nNewLastPara, ::sal_Int32 nNewLastPos)
2190 {
2191 	if (m_nSelectionFirstPara == -1)
2192 		return -1;
2193 	::sal_Int32 Osp = m_nSelectionFirstPara, Osl = m_nSelectionFirstPos, Oep = m_nSelectionLastPara, Oel = m_nSelectionLastPos;
2194 	::sal_Int32 Nsp = nNewFirstPara, Nsl = nNewFirstPos, Nep = nNewLastPara, Nel = nNewLastPos;
2195 	TextPaM Ns(Nsp, sal_uInt16(Nsl));
2196 	TextPaM Ne(Nep, sal_uInt16(Nel));
2197 	TextPaM Os(Osp, sal_uInt16(Osl));
2198 	TextPaM Oe(Oep, sal_uInt16(Oel));
2199 
2200 	if (Os == Oe && Ns == Ne)
2201 	{
2202 		//only caret moves.
2203 		return 1;
2204 	}
2205 	else if (Os == Oe && Ns != Ne)
2206 	{
2207 		//old has no selection but new has selection
2208 		return 2;
2209 	}
2210 	else if (Os != Oe && Ns == Ne)
2211 	{
2212 		//old has selection but new has no selection.
2213 		return 3;
2214 	}
2215 	else if (Os != Oe && Ns != Ne && Osp == Nsp && Osl == Nsl)
2216 	{
2217 		//both old and new have selections.
2218 		if (Oep == Nep )
2219 		{
2220 			//Send text_selection_change event on Nep
2221 
2222 			return 4;
2223 		}
2224 		else if (Oep < Nep)
2225 		{
2226 			//all the following examples like 1,2->1,3 means that old start select para is 1, old end select para is 2,
2227 			// then press shift up, the new start select para is 1, new end select para is 3;
2228 			//for example, 1, 2 -> 1, 3; 4,1 -> 4, 7; 4,1 -> 4, 2; 4,4->4,5
2229 			if (Nep >= Nsp)
2230 			{
2231 				// 1, 2 -> 1, 3; 4, 1 -> 4, 7; 4,4->4,5;
2232 				if (Oep < Osp)
2233 				{
2234 					// 4,1 -> 4,7;
2235 					return 5;
2236 				}
2237 				else if (Oep >= Osp)
2238 				{
2239 					// 1, 2 -> 1, 3; 4,4->4,5;
2240 					return 6;
2241 				}
2242 			}
2243 			else
2244 			{
2245 				// 4,1 -> 4,2,
2246 				if (Oep < Osp)
2247 				{
2248 					// 4,1 -> 4,2,
2249 					return 7;
2250 				}
2251 				else if (Oep >= Osp)
2252 				{
2253 					// no such condition. Oep > Osp = Nsp > Nep
2254 				}
2255 			}
2256 		}
2257 		else if (Oep > Nep)
2258 		{
2259 			// 3,2 -> 3,1; 4,7 -> 4,1; 4, 7 -> 4,6; 4,4 -> 4,3
2260 			if (Nep >= Nsp)
2261 			{
2262 				// 4,7 -> 4,6
2263 				if (Oep <= Osp)
2264 				{
2265 					//no such condition, Oep<Osp=Nsp <= Nep
2266 				}
2267 				else if (Oep > Osp)
2268 				{
2269 					// 4,7 ->4,6
2270 					return 8;
2271 				}
2272 			}
2273 			else
2274 			{
2275 				// 3,2 -> 3,1, 4,7 -> 4,1; 4,4->4,3
2276 				if (Oep <= Osp)
2277 				{
2278 					// 3,2 -> 3,1; 4,4->4,3
2279 					return 9;
2280 				}
2281 				else if (Oep > Osp)
2282 				{
2283 					// 4,7 -> 4,1
2284 					return 10;
2285 				}
2286 			}
2287 		}
2288 	}
2289 	return -1;
2290 }
2291 
2292 
2293 void Document::sendEvent(::sal_Int32 start, ::sal_Int32 end, ::sal_Int16 nEventId)
2294 {
2295 	 Paragraphs::iterator aEnd = ::std::min(m_xParagraphs->begin() + end + 1, m_aVisibleEnd);
2296 	for (Paragraphs::iterator aIt = ::std::max(m_xParagraphs->begin() + start, m_aVisibleBegin);
2297 	     aIt < aEnd; ++aIt)
2298 	{
2299 	    ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(aIt));
2300 	    if (xParagraph.is())
2301 	        xParagraph->notifyEvent(
2302 			nEventId,
2303 	            ::css::uno::Any(), ::css::uno::Any());
2304 	}
2305 }
2306 
2307 void Document::handleSelectionChangeNotification()
2308 {
2309     ::TextSelection const & rSelection = m_rView.GetSelection();
2310     OSL_ENSURE(rSelection.GetStart().GetPara() < m_xParagraphs->size()
2311                && rSelection.GetEnd().GetPara() < m_xParagraphs->size(),
2312                "bad TEXT_HINT_VIEWSELECTIONCHANGED event");
2313     ::sal_Int32 nNewFirstPara
2314           = static_cast< ::sal_Int32 >(rSelection.GetStart().GetPara());
2315     ::sal_Int32 nNewFirstPos
2316           = static_cast< ::sal_Int32 >(rSelection.GetStart().GetIndex());
2317         // XXX  numeric overflow
2318     ::sal_Int32 nNewLastPara
2319           = static_cast< ::sal_Int32 >(rSelection.GetEnd().GetPara());
2320     ::sal_Int32 nNewLastPos
2321           = static_cast< ::sal_Int32 >(rSelection.GetEnd().GetIndex());
2322         // XXX  numeric overflow
2323 
2324     // Lose focus:
2325     Paragraphs::iterator aIt(m_xParagraphs->begin() + nNewLastPara);
2326     if (m_aFocused != m_xParagraphs->end() && m_aFocused != aIt
2327         && m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd)
2328     {
2329         ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(m_aFocused));
2330         if (xParagraph.is())
2331             xParagraph->notifyEvent(
2332                 ::css::accessibility::AccessibleEventId::
2333                 STATE_CHANGED,
2334                 ::css::uno::makeAny(
2335                     ::css::accessibility::AccessibleStateType::FOCUSED),
2336                 ::css::uno::Any());
2337     }
2338 
2339     // Gain focus and update cursor position:
2340     if (aIt >= m_aVisibleBegin && aIt < m_aVisibleEnd
2341         && (aIt != m_aFocused
2342             || nNewLastPara != m_nSelectionLastPara
2343             || nNewLastPos != m_nSelectionLastPos))
2344     {
2345         ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(aIt));
2346         if (xParagraph.is())
2347         {
2348 		//disable the first event when user types in empty field.
2349 		::sal_Int32 count = getAccessibleChildCount();
2350 		::sal_Bool bEmpty = count > 1;
2351             //if (aIt != m_aFocused)
2352 			if (aIt != m_aFocused && bEmpty)
2353                 xParagraph->notifyEvent(
2354                     ::css::accessibility::AccessibleEventId::
2355                     STATE_CHANGED,
2356                     ::css::uno::Any(),
2357                     ::css::uno::makeAny(
2358                         ::css::accessibility::AccessibleStateType::FOCUSED));
2359             if (nNewLastPara != m_nSelectionLastPara
2360                 || nNewLastPos != m_nSelectionLastPos)
2361                 xParagraph->notifyEvent(
2362                     ::css::accessibility::AccessibleEventId::
2363                     CARET_CHANGED,
2364                     ::css::uno::makeAny< ::sal_Int32 >(
2365                         nNewLastPara == m_nSelectionLastPara
2366                         ? m_nSelectionLastPos : 0),
2367                     ::css::uno::makeAny(nNewLastPos));
2368         }
2369     }
2370     m_aFocused = aIt;
2371 
2372     ::sal_Int32 nMin;
2373     ::sal_Int32 nMax;
2374     ::sal_Int32 ret = getSelectionType(nNewFirstPara, nNewFirstPos, nNewLastPara, nNewLastPos);
2375 	switch (ret)
2376 	{
2377 		case -1:
2378 			{
2379 				//no event
2380 			}
2381 			break;
2382 		case 1:
2383 			{
2384 				//only caret moved, already handled in above
2385 			}
2386 			break;
2387 		case 2:
2388 			{
2389 				//old has no selection but new has selection
2390 				nMin = ::std::min(nNewFirstPara, nNewLastPara);
2391 				nMax = ::std::max(nNewFirstPara, nNewLastPara);
2392 				sendEvent(nMin, nMax,  ::css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2393 				sendEvent(nMin, nMax,  ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2394 			}
2395 			break;
2396 		case 3:
2397 			{
2398 				//old has selection but new has no selection.
2399 				nMin = ::std::min(m_nSelectionFirstPara, m_nSelectionLastPara);
2400 				nMax = ::std::max(m_nSelectionFirstPara, m_nSelectionLastPara);
2401 				sendEvent(nMin, nMax,  ::css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2402 				sendEvent(nMin, nMax,  ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2403 			}
2404 			break;
2405 		case 4:
2406 			{
2407 				//Send text_selection_change event on Nep
2408 				sendEvent(nNewLastPara, nNewLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2409 			}
2410 			break;
2411 		case 5:
2412 			{
2413 				// 4, 1 -> 4, 7
2414 				sendEvent(m_nSelectionLastPara, m_nSelectionFirstPara-1, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2415 				sendEvent(nNewFirstPara+1, nNewLastPara, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2416 
2417 				sendEvent(m_nSelectionLastPara, nNewLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2418 			}
2419 			break;
2420 		case 6:
2421 			{
2422 				// 1, 2 -> 1, 4; 4,4->4,5;
2423 				sendEvent(m_nSelectionLastPara+1, nNewLastPara, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2424 
2425 				sendEvent(m_nSelectionLastPara, nNewLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2426 			}
2427 			break;
2428 		case 7:
2429 			{
2430 				// 4,1 -> 4,3,
2431 				sendEvent(m_nSelectionLastPara +1, nNewLastPara , ::css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2432 
2433 				sendEvent(m_nSelectionLastPara, nNewLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2434 			}
2435 			break;
2436 		case 8:
2437 			{
2438 				// 4,7 ->4,5;
2439 				sendEvent(nNewLastPara + 1, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2440 
2441 				sendEvent(nNewLastPara, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2442 			}
2443 			break;
2444 		case 9:
2445 			{
2446 				// 3,2 -> 3,1; 4,4->4,3
2447 				sendEvent(nNewLastPara, m_nSelectionLastPara - 1, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2448 
2449 				sendEvent(nNewLastPara, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2450 			}
2451 			break;
2452 		case 10:
2453 			{
2454 				// 4,7 -> 4,1
2455 				sendEvent(m_nSelectionFirstPara + 1, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2456 				sendEvent(nNewLastPara, nNewFirstPara - 1, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED);
2457 
2458 				sendEvent(nNewLastPara, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED);
2459 			}
2460 			break;
2461 		default:
2462 			break;
2463 	}
2464 
2465     /*
2466     // Update both old and new selection.  (Regardless of how the two selections
2467     // look like, there will always be two ranges to the left and right of the
2468     // overlap---the overlap and/or the range to the right of it possibly being
2469     // empty.  Only for these two ranges notifications have to be sent.)
2470 
2471     TextPaM aOldTextStart( static_cast< sal_uLong >( m_nSelectionFirstPara ), static_cast< sal_uInt16 >( m_nSelectionFirstPos ) );
2472     TextPaM aOldTextEnd( static_cast< sal_uLong >( m_nSelectionLastPara ), static_cast< sal_uInt16 >( m_nSelectionLastPos ) );
2473     TextPaM aNewTextStart( static_cast< sal_uLong >( nNewFirstPara ), static_cast< sal_uInt16 >( nNewFirstPos ) );
2474     TextPaM aNewTextEnd( static_cast< sal_uLong >( nNewLastPara ), static_cast< sal_uInt16 >( nNewLastPos ) );
2475 
2476     // justify selections
2477     justifySelection( aOldTextStart, aOldTextEnd );
2478     justifySelection( aNewTextStart, aNewTextEnd );
2479 
2480     sal_Int32 nFirst1;
2481     sal_Int32 nLast1;
2482     sal_Int32 nFirst2;
2483     sal_Int32 nLast2;
2484 
2485     if ( m_nSelectionFirstPara == -1 )
2486     {
2487         // old selection not initialized yet => notify events only for new selection (if not empty)
2488         nFirst1 = aNewTextStart.GetPara();
2489         nLast1 = aNewTextEnd.GetPara() + ( aNewTextStart != aNewTextEnd ? 1 : 0 );
2490         nFirst2 = 0;
2491         nLast2 = 0;
2492     }
2493     else if ( aOldTextStart == aOldTextEnd && aNewTextStart == aNewTextEnd )
2494     {
2495         // old an new selection empty => no events
2496         nFirst1 = 0;
2497         nLast1 = 0;
2498         nFirst2 = 0;
2499         nLast2 = 0;
2500     }
2501     else if ( aOldTextStart != aOldTextEnd && aNewTextStart == aNewTextEnd )
2502     {
2503         // old selection not empty + new selection empty => notify events only for old selection
2504         nFirst1 = aOldTextStart.GetPara();
2505         nLast1 = aOldTextEnd.GetPara() + 1;
2506         nFirst2 = 0;
2507         nLast2 = 0;
2508     }
2509     else if ( aOldTextStart == aOldTextEnd && aNewTextStart != aNewTextEnd )
2510     {
2511         // old selection empty + new selection not empty => notify events only for new selection
2512         nFirst1 = aNewTextStart.GetPara();
2513         nLast1 = aNewTextEnd.GetPara() + 1;
2514         nFirst2 = 0;
2515         nLast2 = 0;
2516     }
2517     else
2518     {
2519         // old and new selection not empty => notify events for the two ranges left and right of the overlap
2520         ::std::vector< TextPaM > aTextPaMs(4);
2521         aTextPaMs[0] = aOldTextStart;
2522         aTextPaMs[1] = aOldTextEnd;
2523         aTextPaMs[2] = aNewTextStart;
2524         aTextPaMs[3] = aNewTextEnd;
2525         ::std::sort( aTextPaMs.begin(), aTextPaMs.end() );
2526 
2527         nFirst1 = aTextPaMs[0].GetPara();
2528         nLast1 = aTextPaMs[1].GetPara() + ( aTextPaMs[0] != aTextPaMs[1] ? 1 : 0 );
2529 
2530         nFirst2 = aTextPaMs[2].GetPara();
2531         nLast2 = aTextPaMs[3].GetPara() + ( aTextPaMs[2] != aTextPaMs[3] ? 1 : 0 );
2532 
2533         // adjust overlapping ranges
2534         if ( nLast1 > nFirst2 )
2535             nLast1 = nFirst2;
2536     }
2537 
2538     // notify selection changes
2539     notifySelectionChange( nFirst1, nLast1 );
2540     notifySelectionChange( nFirst2, nLast2 );
2541 	*/
2542     m_nSelectionFirstPara = nNewFirstPara;
2543     m_nSelectionFirstPos = nNewFirstPos;
2544     m_nSelectionLastPara = nNewLastPara;
2545     m_nSelectionLastPos = nNewLastPos;
2546 }
2547 
2548 void Document::notifySelectionChange( sal_Int32 nFirst, sal_Int32 nLast )
2549 {
2550     if ( nFirst < nLast )
2551     {
2552         Paragraphs::iterator aEnd( ::std::min( m_xParagraphs->begin() + nLast, m_aVisibleEnd ) );
2553         for ( Paragraphs::iterator aIt = ::std::max( m_xParagraphs->begin() + nFirst, m_aVisibleBegin ); aIt < aEnd; ++aIt )
2554         {
2555             ::rtl::Reference< ParagraphImpl > xParagraph( getParagraph( aIt ) );
2556             if ( xParagraph.is() )
2557             {
2558                 xParagraph->notifyEvent(
2559                     ::css::accessibility::AccessibleEventId::SELECTION_CHANGED,
2560                     ::css::uno::Any(), ::css::uno::Any() );
2561                 xParagraph->notifyEvent(
2562                     ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED,
2563                     ::css::uno::Any(), ::css::uno::Any() );
2564             }
2565         }
2566     }
2567 }
2568 
2569 void Document::justifySelection( TextPaM& rTextStart, TextPaM& rTextEnd )
2570 {
2571     if ( rTextStart > rTextEnd )
2572     {
2573         TextPaM aTextPaM( rTextStart );
2574         rTextStart = rTextEnd;
2575         rTextEnd = aTextPaM;
2576     }
2577 }
2578 
2579 void Document::disposeParagraphs()
2580 {
2581     for (Paragraphs::iterator aIt(m_xParagraphs->begin());
2582          aIt != m_xParagraphs->end(); ++aIt)
2583     {
2584         ::css::uno::Reference< ::css::lang::XComponent > xComponent(
2585             aIt->getParagraph().get(), ::css::uno::UNO_QUERY);
2586         if (xComponent.is())
2587             xComponent->dispose();
2588     }
2589 }
2590 
2591 // static
2592 ::css::uno::Any Document::mapFontColor(::Color const & rColor)
2593 {
2594     return ::css::uno::makeAny(
2595         static_cast< ::sal_Int32 >(COLORDATA_RGB(rColor.GetColor())));
2596         // FIXME  keep transparency?
2597 }
2598 
2599 // static
2600 ::Color Document::mapFontColor(::css::uno::Any const & rColor)
2601 {
2602     ::sal_Int32 nColor = 0;
2603     rColor >>= nColor;
2604     return ::Color(static_cast< ::ColorData >(nColor));
2605 }
2606 
2607 // static
2608 ::css::uno::Any Document::mapFontWeight(::FontWeight nWeight)
2609 {
2610     // Map from ::FontWeight to ::css:awt::FontWeight, depends on order of
2611     // elements in ::FontWeight (vcl/vclenum.hxx):
2612     static float const aWeight[]
2613         = { ::css::awt::FontWeight::DONTKNOW, // WEIGHT_DONTKNOW
2614             ::css::awt::FontWeight::THIN, // WEIGHT_THIN
2615             ::css::awt::FontWeight::ULTRALIGHT, // WEIGHT_ULTRALIGHT
2616             ::css::awt::FontWeight::LIGHT, // WEIGHT_LIGHT
2617             ::css::awt::FontWeight::SEMILIGHT, // WEIGHT_SEMILIGHT
2618             ::css::awt::FontWeight::NORMAL, // WEIGHT_NORMAL
2619             ::css::awt::FontWeight::NORMAL, // WEIGHT_MEDIUM
2620             ::css::awt::FontWeight::SEMIBOLD, // WEIGHT_SEMIBOLD
2621             ::css::awt::FontWeight::BOLD, // WEIGHT_BOLD
2622             ::css::awt::FontWeight::ULTRABOLD, // WEIGHT_ULTRABOLD
2623             ::css::awt::FontWeight::BLACK }; // WEIGHT_BLACK
2624     return ::css::uno::makeAny(aWeight[nWeight]);
2625 }
2626 
2627 // static
2628 ::FontWeight Document::mapFontWeight(::css::uno::Any const & rWeight)
2629 {
2630     float nWeight = ::css::awt::FontWeight::NORMAL;
2631     rWeight >>= nWeight;
2632     return nWeight <= ::css::awt::FontWeight::DONTKNOW ? WEIGHT_DONTKNOW
2633         : nWeight <= ::css::awt::FontWeight::THIN ? WEIGHT_THIN
2634         : nWeight <= ::css::awt::FontWeight::ULTRALIGHT ? WEIGHT_ULTRALIGHT
2635         : nWeight <= ::css::awt::FontWeight::LIGHT ? WEIGHT_LIGHT
2636         : nWeight <= ::css::awt::FontWeight::SEMILIGHT ? WEIGHT_SEMILIGHT
2637         : nWeight <= ::css::awt::FontWeight::NORMAL ? WEIGHT_NORMAL
2638         : nWeight <= ::css::awt::FontWeight::SEMIBOLD ? WEIGHT_SEMIBOLD
2639         : nWeight <= ::css::awt::FontWeight::BOLD ? WEIGHT_BOLD
2640         : nWeight <= ::css::awt::FontWeight::ULTRABOLD ? WEIGHT_ULTRABOLD
2641         : WEIGHT_BLACK;
2642 }
2643 
2644 }
2645 
2646