Impress Remote 1.0.5, tag sdremote-1.0.5
[LibreOffice.git] / accessibility / source / extended / textwindowaccessibility.cxx
blob71e6c780cf9225d3d337b0e2aa2a4b617326c2ee
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <accessibility/extended/textwindowaccessibility.hxx>
21 #include "comphelper/accessibleeventnotifier.hxx"
22 #include "unotools/accessiblerelationsethelper.hxx"
23 #include <unotools/accessiblestatesethelper.hxx>
24 #include <vcl/window.hxx>
25 #include <toolkit/helper/convert.hxx>
27 #include <algorithm>
28 #include <vector>
29 #include <boost/unordered_map.hpp>
31 namespace accessibility
34 // Both ::osl::Mutex and ParagraphBase implement acquire and release, and thus
35 // ::rtl::Reference< Paragraph > does not work. So ParagraphImpl was factored
36 // out and ::rtl::Reference< ParagraphImpl > is used instead.
37 class Paragraph: private ::osl::Mutex, public ParagraphImpl
39 public:
40 inline Paragraph(::rtl::Reference< Document > const & rDocument,
41 Paragraphs::size_type nNumber):
42 ParagraphImpl(rDocument, nNumber, *this) {}
45 void SfxListenerGuard::startListening(::SfxBroadcaster & rNotifier)
47 OSL_ENSURE(m_pNotifier == 0, "called more than once");
48 m_pNotifier = &rNotifier;
49 m_rListener.StartListening(*m_pNotifier, true);
52 void SfxListenerGuard::endListening()
54 if (m_pNotifier != 0)
56 m_rListener.EndListening(*m_pNotifier);
57 m_pNotifier = 0;
61 void WindowListenerGuard::startListening(::Window & rNotifier)
63 OSL_ENSURE(m_pNotifier == 0, "called more than once");
64 m_pNotifier = &rNotifier;
65 m_pNotifier->AddEventListener(m_aListener);
68 void WindowListenerGuard::endListening()
70 if (m_pNotifier != 0)
72 m_pNotifier->RemoveEventListener(m_aListener);
73 m_pNotifier = 0;
77 ParagraphImpl::ParagraphImpl(::rtl::Reference< Document > const & rDocument,
78 Paragraphs::size_type nNumber,
79 ::osl::Mutex & rMutex):
80 ParagraphBase(rMutex),
81 m_xDocument(rDocument),
82 m_nNumber(nNumber),
83 m_nClientId(0)
85 m_aParagraphText = m_xDocument->retrieveParagraphText(this);
88 void
89 ParagraphImpl::numberChanged(bool bIncremented)
91 if (bIncremented)
92 ++m_nNumber;
93 else
94 --m_nNumber;
97 void ParagraphImpl::textChanged()
99 OUString aParagraphText = implGetText();
100 ::css::uno::Any aOldValue, aNewValue;
101 if ( implInitTextChangedEvent( m_aParagraphText, aParagraphText, aOldValue, aNewValue ) )
103 m_aParagraphText = aParagraphText;
104 notifyEvent(::css::accessibility::AccessibleEventId::
105 TEXT_CHANGED,
106 aOldValue, aNewValue);
110 void ParagraphImpl::notifyEvent(::sal_Int16 nEventId,
111 ::css::uno::Any const & rOldValue,
112 ::css::uno::Any const & rNewValue)
114 if (m_nClientId)
115 comphelper::AccessibleEventNotifier::addEvent( m_nClientId, ::css::accessibility::AccessibleEventObject(
116 static_cast< ::cppu::OWeakObject * >(this),
117 nEventId, rNewValue, rOldValue) );
120 // virtual
121 ::css::uno::Reference< ::css::accessibility::XAccessibleContext > SAL_CALL
122 ParagraphImpl::getAccessibleContext() throw (::css::uno::RuntimeException)
124 checkDisposed();
125 return this;
128 // virtual
129 ::sal_Int32 SAL_CALL ParagraphImpl::getAccessibleChildCount()
130 throw (::css::uno::RuntimeException)
132 checkDisposed();
133 return 0;
136 // virtual
137 ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL
138 ParagraphImpl::getAccessibleChild(::sal_Int32)
139 throw (::css::lang::IndexOutOfBoundsException,
140 ::css::uno::RuntimeException)
142 checkDisposed();
143 throw ::css::lang::IndexOutOfBoundsException(
144 "textwindowaccessibility.cxx:"
145 " ParagraphImpl::getAccessibleChild",
146 static_cast< ::css::uno::XWeak * >(this));
149 // virtual
150 ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL
151 ParagraphImpl::getAccessibleParent()
152 throw (::css::uno::RuntimeException)
154 checkDisposed();
155 return m_xDocument->getAccessible();
158 // virtual
159 ::sal_Int32 SAL_CALL ParagraphImpl::getAccessibleIndexInParent()
160 throw (::css::uno::RuntimeException)
162 checkDisposed();
163 return m_xDocument->retrieveParagraphIndex(this);
166 // virtual
167 ::sal_Int16 SAL_CALL ParagraphImpl::getAccessibleRole()
168 throw (::css::uno::RuntimeException)
170 checkDisposed();
171 return ::css::accessibility::AccessibleRole::PARAGRAPH;
174 // virtual
175 OUString SAL_CALL ParagraphImpl::getAccessibleDescription()
176 throw (::css::uno::RuntimeException)
178 checkDisposed();
179 return OUString();
182 // virtual
183 OUString SAL_CALL ParagraphImpl::getAccessibleName()
184 throw (::css::uno::RuntimeException)
186 checkDisposed();
187 return OUString();
190 // virtual
191 ::css::uno::Reference< ::css::accessibility::XAccessibleRelationSet >
192 SAL_CALL ParagraphImpl::getAccessibleRelationSet()
193 throw (::css::uno::RuntimeException)
195 checkDisposed();
196 return m_xDocument->retrieveParagraphRelationSet( this );
199 // virtual
200 ::css::uno::Reference< ::css::accessibility::XAccessibleStateSet >
201 SAL_CALL ParagraphImpl::getAccessibleStateSet()
202 throw (::css::uno::RuntimeException)
204 checkDisposed();
206 // FIXME Notification of changes (STATE_CHANGED) missing when
207 // m_rView.IsReadOnly() changes:
208 return new ::utl::AccessibleStateSetHelper(
209 m_xDocument->retrieveParagraphState(this));
212 // virtual
213 ::css::lang::Locale SAL_CALL ParagraphImpl::getLocale()
214 throw (::css::accessibility::IllegalAccessibleComponentStateException,
215 ::css::uno::RuntimeException)
217 checkDisposed();
218 return m_xDocument->retrieveLocale();
221 // virtual
222 ::sal_Bool SAL_CALL ParagraphImpl::containsPoint(::css::awt::Point const & rPoint)
223 throw (::css::uno::RuntimeException)
225 checkDisposed();
226 ::css::awt::Rectangle aRect(m_xDocument->retrieveParagraphBounds(this,
227 false));
228 return rPoint.X >= 0 && rPoint.X < aRect.Width
229 && rPoint.Y >= 0 && rPoint.Y < aRect.Height;
232 // virtual
233 ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL
234 ParagraphImpl::getAccessibleAtPoint(::css::awt::Point const &)
235 throw (::css::uno::RuntimeException)
237 checkDisposed();
238 return 0;
241 // virtual
242 ::css::awt::Rectangle SAL_CALL ParagraphImpl::getBounds()
243 throw (::css::uno::RuntimeException)
245 checkDisposed();
246 return m_xDocument->retrieveParagraphBounds(this, false);
249 // virtual
250 ::css::awt::Point SAL_CALL ParagraphImpl::getLocation()
251 throw (::css::uno::RuntimeException)
253 checkDisposed();
254 ::css::awt::Rectangle aRect(m_xDocument->retrieveParagraphBounds(this,
255 false));
256 return ::css::awt::Point(aRect.X, aRect.Y);
259 // virtual
260 ::css::awt::Point SAL_CALL ParagraphImpl::getLocationOnScreen()
261 throw (::css::uno::RuntimeException)
263 checkDisposed();
264 ::css::awt::Rectangle aRect(m_xDocument->retrieveParagraphBounds(this,
265 true));
266 return ::css::awt::Point(aRect.X, aRect.Y);
269 // virtual
270 ::css::awt::Size SAL_CALL ParagraphImpl::getSize()
271 throw (::css::uno::RuntimeException)
273 checkDisposed();
274 ::css::awt::Rectangle aRect(m_xDocument->retrieveParagraphBounds(this,
275 false));
276 return ::css::awt::Size(aRect.Width, aRect.Height);
279 // virtual
280 void SAL_CALL ParagraphImpl::grabFocus() throw (::css::uno::RuntimeException)
282 checkDisposed();
283 Window* pWindow = m_xDocument->GetWindow();
284 if ( pWindow )
286 pWindow->GrabFocus();
290 m_xDocument->changeParagraphSelection(this, 0, 0);
292 catch (const ::css::lang::IndexOutOfBoundsException & rEx)
294 OSL_TRACE(
295 "textwindowaccessibility.cxx: ParagraphImpl::grabFocus:"
296 " caught unexpected %s\n",
297 OUStringToOString(rEx.Message, RTL_TEXTENCODING_UTF8).
298 getStr());
302 // virtual
303 ::css::uno::Any SAL_CALL ParagraphImpl::getAccessibleKeyBinding()
304 throw (::css::uno::RuntimeException)
306 checkDisposed();
307 return ::css::uno::Any();
310 // virtual
311 ::css::util::Color SAL_CALL ParagraphImpl::getForeground()
312 throw (::css::uno::RuntimeException)
314 return 0; // TODO
317 // virtual
318 ::css::util::Color SAL_CALL ParagraphImpl::getBackground()
319 throw (::css::uno::RuntimeException)
321 return 0; // TODO
324 // virtual
325 ::sal_Int32 SAL_CALL ParagraphImpl::getCaretPosition()
326 throw (::css::uno::RuntimeException)
328 checkDisposed();
329 return m_xDocument->retrieveParagraphCaretPosition(this);
332 // virtual
333 ::sal_Bool SAL_CALL ParagraphImpl::setCaretPosition(::sal_Int32 nIndex)
334 throw (::css::lang::IndexOutOfBoundsException,
335 ::css::uno::RuntimeException)
337 checkDisposed();
338 m_xDocument->changeParagraphSelection(this, nIndex, nIndex);
339 return true;
342 // virtual
343 ::sal_Unicode SAL_CALL ParagraphImpl::getCharacter(::sal_Int32 nIndex)
344 throw (::css::lang::IndexOutOfBoundsException,
345 ::css::uno::RuntimeException)
347 checkDisposed();
348 return OCommonAccessibleText::getCharacter(nIndex);
351 // virtual
352 ::css::uno::Sequence< ::css::beans::PropertyValue > SAL_CALL
353 ParagraphImpl::getCharacterAttributes(::sal_Int32 nIndex, const ::com::sun::star::uno::Sequence< OUString >& aRequestedAttributes)
354 throw (::css::lang::IndexOutOfBoundsException,
355 ::css::uno::RuntimeException)
357 checkDisposed();
358 return m_xDocument->retrieveCharacterAttributes( this, nIndex, aRequestedAttributes );
361 // virtual
362 ::css::awt::Rectangle SAL_CALL
363 ParagraphImpl::getCharacterBounds(::sal_Int32 nIndex)
364 throw (::css::lang::IndexOutOfBoundsException,
365 ::css::uno::RuntimeException)
367 checkDisposed();
368 ::css::awt::Rectangle aBounds(m_xDocument->retrieveCharacterBounds(this, nIndex));
369 ::css::awt::Rectangle aParaBounds(m_xDocument->retrieveParagraphBounds(this, false));
370 aBounds.X -= aParaBounds.X;
371 aBounds.Y -= aParaBounds.Y;
372 return aBounds;
375 // virtual
376 ::sal_Int32 SAL_CALL ParagraphImpl::getCharacterCount()
377 throw (::css::uno::RuntimeException)
379 checkDisposed();
380 return OCommonAccessibleText::getCharacterCount();
383 // virtual
384 ::sal_Int32 SAL_CALL
385 ParagraphImpl::getIndexAtPoint(::css::awt::Point const & rPoint)
386 throw (::css::uno::RuntimeException)
388 checkDisposed();
389 ::css::awt::Point aPoint(rPoint);
390 ::css::awt::Rectangle aParaBounds(m_xDocument->retrieveParagraphBounds(this, false));
391 aPoint.X += aParaBounds.X;
392 aPoint.Y += aParaBounds.Y;
393 return m_xDocument->retrieveCharacterIndex(this, aPoint);
396 // virtual
397 OUString SAL_CALL ParagraphImpl::getSelectedText()
398 throw (::css::uno::RuntimeException)
400 checkDisposed();
402 return OCommonAccessibleText::getSelectedText();
405 // virtual
406 ::sal_Int32 SAL_CALL ParagraphImpl::getSelectionStart()
407 throw (::css::uno::RuntimeException)
409 checkDisposed();
410 return OCommonAccessibleText::getSelectionStart();
413 // virtual
414 ::sal_Int32 SAL_CALL ParagraphImpl::getSelectionEnd()
415 throw (::css::uno::RuntimeException)
417 checkDisposed();
418 return OCommonAccessibleText::getSelectionEnd();
421 // virtual
422 ::sal_Bool SAL_CALL ParagraphImpl::setSelection(::sal_Int32 nStartIndex,
423 ::sal_Int32 nEndIndex)
424 throw (::css::lang::IndexOutOfBoundsException,
425 ::css::uno::RuntimeException)
427 checkDisposed();
428 m_xDocument->changeParagraphSelection(this, nStartIndex, nEndIndex);
429 return true;
432 // virtual
433 OUString SAL_CALL ParagraphImpl::getText()
434 throw (::css::uno::RuntimeException)
436 checkDisposed();
437 return OCommonAccessibleText::getText();
440 // virtual
441 OUString SAL_CALL ParagraphImpl::getTextRange(::sal_Int32 nStartIndex,
442 ::sal_Int32 nEndIndex)
443 throw (::css::lang::IndexOutOfBoundsException,
444 ::css::uno::RuntimeException)
446 checkDisposed();
447 return OCommonAccessibleText::getTextRange(nStartIndex, nEndIndex);
450 // virtual
451 ::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)
453 checkDisposed();
454 return OCommonAccessibleText::getTextAtIndex(nIndex, aTextType);
457 // virtual
458 ::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)
460 checkDisposed();
461 return OCommonAccessibleText::getTextBeforeIndex(nIndex, aTextType);
464 // virtual
465 ::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)
467 checkDisposed();
468 return OCommonAccessibleText::getTextBehindIndex(nIndex, aTextType);
471 // virtual
472 ::sal_Bool SAL_CALL ParagraphImpl::copyText(::sal_Int32 nStartIndex,
473 ::sal_Int32 nEndIndex)
474 throw (::css::lang::IndexOutOfBoundsException,
475 ::css::uno::RuntimeException)
477 checkDisposed();
478 m_xDocument->copyParagraphText(this, nStartIndex, nEndIndex);
479 return true;
482 // virtual
483 ::sal_Bool SAL_CALL ParagraphImpl::cutText(::sal_Int32 nStartIndex,
484 ::sal_Int32 nEndIndex)
485 throw (::css::lang::IndexOutOfBoundsException,
486 ::css::uno::RuntimeException)
488 checkDisposed();
489 m_xDocument->changeParagraphText(this, nStartIndex, nEndIndex, true, false,
490 OUString());
491 return true;
494 // virtual
495 ::sal_Bool SAL_CALL ParagraphImpl::pasteText(::sal_Int32 nIndex)
496 throw (::css::lang::IndexOutOfBoundsException,
497 ::css::uno::RuntimeException)
499 checkDisposed();
500 m_xDocument->changeParagraphText(this, nIndex, nIndex, false, true,
501 OUString());
502 return true;
505 // virtual
506 ::sal_Bool SAL_CALL ParagraphImpl::deleteText(::sal_Int32 nStartIndex,
507 ::sal_Int32 nEndIndex)
508 throw (::css::lang::IndexOutOfBoundsException,
509 ::css::uno::RuntimeException)
511 checkDisposed();
512 m_xDocument->changeParagraphText(this, nStartIndex, nEndIndex, false, false,
513 OUString());
514 return true;
517 // virtual
518 ::sal_Bool SAL_CALL ParagraphImpl::insertText(OUString const & rText,
519 ::sal_Int32 nIndex)
520 throw (::css::lang::IndexOutOfBoundsException,
521 ::css::uno::RuntimeException)
523 checkDisposed();
524 m_xDocument->changeParagraphText(this, nIndex, nIndex, false, false, rText);
525 return true;
528 // virtual
529 ::sal_Bool SAL_CALL
530 ParagraphImpl::replaceText(::sal_Int32 nStartIndex, ::sal_Int32 nEndIndex,
531 OUString const & rReplacement)
532 throw (::css::lang::IndexOutOfBoundsException,
533 ::css::uno::RuntimeException)
535 checkDisposed();
536 m_xDocument->changeParagraphText(this, nStartIndex, nEndIndex, false, false,
537 rReplacement);
538 return true;
541 // virtual
542 ::sal_Bool SAL_CALL ParagraphImpl::setAttributes(
543 ::sal_Int32 nStartIndex, ::sal_Int32 nEndIndex,
544 ::css::uno::Sequence< ::css::beans::PropertyValue > const & rAttributeSet)
545 throw (::css::lang::IndexOutOfBoundsException,
546 ::css::uno::RuntimeException)
548 checkDisposed();
549 m_xDocument->changeParagraphAttributes(this, nStartIndex, nEndIndex,
550 rAttributeSet);
551 return true;
554 // virtual
555 ::sal_Bool SAL_CALL ParagraphImpl::setText(OUString const & rText)
556 throw (::css::uno::RuntimeException)
558 checkDisposed();
559 m_xDocument->changeParagraphText(this, rText);
560 return true;
563 // virtual
564 ::css::uno::Sequence< ::css::beans::PropertyValue > SAL_CALL
565 ParagraphImpl::getDefaultAttributes(const ::css::uno::Sequence< OUString >& RequestedAttributes)
566 throw (::css::uno::RuntimeException)
568 checkDisposed();
569 return m_xDocument->retrieveDefaultAttributes( this, RequestedAttributes );
572 // virtual
573 ::css::uno::Sequence< ::css::beans::PropertyValue > SAL_CALL
574 ParagraphImpl::getRunAttributes(::sal_Int32 Index, const ::css::uno::Sequence< OUString >& RequestedAttributes)
575 throw (::css::lang::IndexOutOfBoundsException,
576 ::css::uno::RuntimeException)
578 checkDisposed();
579 return m_xDocument->retrieveRunAttributes( this, Index, RequestedAttributes );
582 // virtual
583 ::sal_Int32 SAL_CALL ParagraphImpl::getLineNumberAtIndex( ::sal_Int32 nIndex )
584 throw (::css::lang::IndexOutOfBoundsException,
585 ::css::uno::RuntimeException)
587 checkDisposed();
589 ::sal_Int32 nLineNo = -1;
590 m_xDocument->retrieveParagraphLineBoundary( this, nIndex, &nLineNo );
592 return nLineNo;
595 // virtual
596 ::css::accessibility::TextSegment SAL_CALL ParagraphImpl::getTextAtLineNumber( ::sal_Int32 nLineNo )
597 throw (::css::lang::IndexOutOfBoundsException,
598 ::css::uno::RuntimeException)
600 checkDisposed();
602 ::css::i18n::Boundary aBoundary =
603 m_xDocument->retrieveParagraphBoundaryOfLine( this, nLineNo );
605 return ::css::accessibility::TextSegment( getTextRange(aBoundary.startPos, aBoundary.endPos),
606 aBoundary.startPos, aBoundary.endPos);
609 // virtual
610 ::css::accessibility::TextSegment SAL_CALL ParagraphImpl::getTextAtLineWithCaret( )
611 throw (::css::uno::RuntimeException)
613 checkDisposed();
615 sal_Int32 nLineNo = getNumberOfLineWithCaret();
617 try {
618 return ( nLineNo >= 0 ) ?
619 getTextAtLineNumber( nLineNo ) :
620 ::css::accessibility::TextSegment();
621 } catch (const ::css::lang::IndexOutOfBoundsException&) {
622 throw ::css::uno::RuntimeException(
623 "textwindowaccessibility.cxx:"
624 " ParagraphImpl::getTextAtLineWithCaret",
625 static_cast< ::css::uno::XWeak * >( this ) );
629 // virtual
630 ::sal_Int32 SAL_CALL ParagraphImpl::getNumberOfLineWithCaret( )
631 throw (::css::uno::RuntimeException)
633 checkDisposed();
634 return m_xDocument->retrieveParagraphLineWithCursor(this);
638 // virtual
639 void SAL_CALL ParagraphImpl::addAccessibleEventListener(
640 ::css::uno::Reference<
641 ::css::accessibility::XAccessibleEventListener > const & rListener)
642 throw (::css::uno::RuntimeException)
644 if (rListener.is())
646 ::osl::ClearableMutexGuard aGuard(rBHelper.rMutex);
647 if (rBHelper.bDisposed || rBHelper.bInDispose)
649 aGuard.clear();
650 rListener->disposing(::css::lang::EventObject(
651 static_cast< ::cppu::OWeakObject * >(this)));
653 else
655 if (!m_nClientId)
656 m_nClientId = comphelper::AccessibleEventNotifier::registerClient( );
657 comphelper::AccessibleEventNotifier::addEventListener( m_nClientId, rListener );
662 // virtual
663 void SAL_CALL ParagraphImpl::removeAccessibleEventListener(
664 ::css::uno::Reference<
665 ::css::accessibility::XAccessibleEventListener > const & rListener)
666 throw (::css::uno::RuntimeException)
668 comphelper::AccessibleEventNotifier::TClientId nId = 0;
670 ::osl::ClearableMutexGuard aGuard(rBHelper.rMutex);
671 if (rListener.is() && m_nClientId != 0
672 && comphelper::AccessibleEventNotifier::removeEventListener( m_nClientId, rListener ) == 0)
674 nId = m_nClientId;
675 m_nClientId = 0;
678 if (nId != 0)
680 // no listeners anymore
681 // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
682 // and at least to us not firing any events anymore, in case somebody calls
683 // NotifyAccessibleEvent, again
684 comphelper::AccessibleEventNotifier::revokeClient(nId);
688 // virtual
689 void SAL_CALL ParagraphImpl::disposing()
691 comphelper::AccessibleEventNotifier::TClientId nId = 0;
693 ::osl::ClearableMutexGuard aGuard(rBHelper.rMutex);
694 nId = m_nClientId;
695 m_nClientId = 0;
697 if (nId != 0)
698 comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing(nId, *this);
701 // virtual
702 OUString ParagraphImpl::implGetText()
704 return m_xDocument->retrieveParagraphText(this);
707 // virtual
708 ::css::lang::Locale ParagraphImpl::implGetLocale()
710 return m_xDocument->retrieveLocale();
713 // virtual
714 void ParagraphImpl::implGetSelection(::sal_Int32 & rStartIndex,
715 ::sal_Int32 & rEndIndex)
717 m_xDocument->retrieveParagraphSelection(this, &rStartIndex, &rEndIndex);
720 // virtual
721 void ParagraphImpl::implGetParagraphBoundary( ::css::i18n::Boundary& rBoundary,
722 ::sal_Int32 nIndex )
724 OUString sText( implGetText() );
725 ::sal_Int32 nLength = sText.getLength();
727 if ( implIsValidIndex( nIndex, nLength ) )
729 rBoundary.startPos = 0;
730 rBoundary.endPos = nLength;
732 else
734 rBoundary.startPos = nIndex;
735 rBoundary.endPos = nIndex;
739 // virtual
740 void ParagraphImpl::implGetLineBoundary( ::css::i18n::Boundary& rBoundary,
741 ::sal_Int32 nIndex )
743 OUString sText( implGetText() );
744 ::sal_Int32 nLength = sText.getLength();
746 if ( implIsValidIndex( nIndex, nLength ) || nIndex == nLength )
748 ::css::i18n::Boundary aBoundary =
749 m_xDocument->retrieveParagraphLineBoundary( this, nIndex );
750 rBoundary.startPos = aBoundary.startPos;
751 rBoundary.endPos = aBoundary.endPos;
753 else
755 rBoundary.startPos = nIndex;
756 rBoundary.endPos = nIndex;
761 void ParagraphImpl::checkDisposed()
763 ::osl::MutexGuard aGuard(rBHelper.rMutex);
764 if (!(rBHelper.bDisposed || rBHelper.bInDispose))
765 return;
766 throw ::css::lang::DisposedException(
767 OUString(), static_cast< ::css::uno::XWeak * >(this));
770 Document::Document(::VCLXWindow * pVclXWindow, ::TextEngine & rEngine,
771 ::TextView & rView, bool bCompoundControlChild):
772 VCLXAccessibleComponent(pVclXWindow),
773 m_xAccessible(pVclXWindow),
774 m_rEngine(rEngine),
775 m_rView(rView),
776 m_aEngineListener(*this),
777 m_aViewListener(LINK(this, Document, WindowEventHandler)),
778 m_bCompoundControlChild(bCompoundControlChild)
781 ::css::lang::Locale Document::retrieveLocale()
783 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
784 return m_rEngine.GetLocale();
787 ::sal_Int32 Document::retrieveParagraphIndex(ParagraphImpl const * pParagraph)
789 ::osl::MutexGuard aInternalGuard(GetMutex());
791 // If a client holds on to a Paragraph that is no longer visible, it can
792 // happen that this Paragraph lies outside the range from m_aVisibleBegin
793 // to m_aVisibleEnd. In that case, return -1 instead of a valid index:
794 Paragraphs::iterator aPara(m_xParagraphs->begin()
795 + pParagraph->getNumber());
796 return aPara < m_aVisibleBegin || aPara >= m_aVisibleEnd
797 ? -1 : static_cast< ::sal_Int32 >(aPara - m_aVisibleBegin);
798 // XXX numeric overflow
801 ::sal_Int64 Document::retrieveParagraphState(ParagraphImpl const * pParagraph)
803 ::osl::MutexGuard aInternalGuard(GetMutex());
805 // If a client holds on to a Paragraph that is no longer visible, it can
806 // happen that this Paragraph lies outside the range from m_aVisibleBegin
807 // to m_aVisibleEnd. In that case, it is neither VISIBLE nor SHOWING:
808 ::sal_Int64 nState
809 = (static_cast< ::sal_Int64 >(1)
810 << ::css::accessibility::AccessibleStateType::ENABLED)
811 | (static_cast< ::sal_Int64 >(1)
812 << ::css::accessibility::AccessibleStateType::SENSITIVE)
813 | (static_cast< ::sal_Int64 >(1)
814 << ::css::accessibility::AccessibleStateType::FOCUSABLE)
815 | (static_cast< ::sal_Int64 >(1)
816 << ::css::accessibility::AccessibleStateType::MULTI_LINE);
817 if (!m_rView.IsReadOnly())
818 nState |= (static_cast< ::sal_Int64 >(1)
819 << ::css::accessibility::AccessibleStateType::EDITABLE);
820 Paragraphs::iterator aPara(m_xParagraphs->begin()
821 + pParagraph->getNumber());
822 if (aPara >= m_aVisibleBegin && aPara < m_aVisibleEnd)
824 nState
825 |= (static_cast< ::sal_Int64 >(1)
826 << ::css::accessibility::AccessibleStateType::VISIBLE)
827 | (static_cast< ::sal_Int64 >(1)
828 << ::css::accessibility::AccessibleStateType::SHOWING);
829 if (aPara == m_aFocused)
830 nState |= (static_cast< ::sal_Int64 >(1)
831 << ::css::accessibility::AccessibleStateType::FOCUSED);
833 return nState;
836 ::css::awt::Rectangle
837 Document::retrieveParagraphBounds(ParagraphImpl const * pParagraph,
838 bool bAbsolute)
840 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
841 ::osl::MutexGuard aInternalGuard(GetMutex());
843 // If a client holds on to a Paragraph that is no longer visible (as it
844 // scrolled out the top of the view), it can happen that this Paragraph
845 // lies before m_aVisibleBegin. In that case, calculate the vertical
846 // position of the Paragraph starting at paragraph 0, otherwise optimize
847 // and start at m_aVisibleBegin:
848 Paragraphs::iterator aPara(m_xParagraphs->begin()
849 + pParagraph->getNumber());
850 ::sal_Int32 nPos;
851 Paragraphs::iterator aIt;
852 if (aPara < m_aVisibleBegin)
854 nPos = 0;
855 aIt = m_xParagraphs->begin();
857 else
859 nPos = m_nViewOffset - m_nVisibleBeginOffset;
860 aIt = m_aVisibleBegin;
862 for (; aIt != aPara; ++aIt)
863 nPos += aIt->getHeight();
865 Point aOrig(0, 0);
866 if (bAbsolute)
867 aOrig = m_rView.GetWindow()->OutputToAbsoluteScreenPixel(aOrig);
869 return ::css::awt::Rectangle(
870 static_cast< ::sal_Int32 >(aOrig.X()),
871 static_cast< ::sal_Int32 >(aOrig.Y()) + nPos - m_nViewOffset,
872 m_rView.GetWindow()->GetOutputSizePixel().Width(), aPara->getHeight());
873 // XXX numeric overflow (3x)
876 OUString
877 Document::retrieveParagraphText(ParagraphImpl const * pParagraph)
879 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
880 ::osl::MutexGuard aInternalGuard(GetMutex());
881 return m_rEngine.GetText(static_cast< ::sal_uLong >(pParagraph->getNumber()));
882 // numeric overflow cannot happen here
885 void Document::retrieveParagraphSelection(ParagraphImpl const * pParagraph,
886 ::sal_Int32 * pBegin,
887 ::sal_Int32 * pEnd)
889 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
890 ::osl::MutexGuard aInternalGuard(GetMutex());
891 ::TextSelection const & rSelection = m_rView.GetSelection();
892 Paragraphs::size_type nNumber = pParagraph->getNumber();
893 TextPaM aStartPaM( rSelection.GetStart() );
894 TextPaM aEndPaM( rSelection.GetEnd() );
895 TextPaM aMinPaM( ::std::min( aStartPaM, aEndPaM ) );
896 TextPaM aMaxPaM( ::std::max( aStartPaM, aEndPaM ) );
898 if ( nNumber >= aMinPaM.GetPara() && nNumber <= aMaxPaM.GetPara() )
900 *pBegin = nNumber > aMinPaM.GetPara()
902 : static_cast< ::sal_Int32 >( aMinPaM.GetIndex() );
903 // XXX numeric overflow
904 *pEnd = nNumber < aMaxPaM.GetPara()
905 ? static_cast< ::sal_Int32 >( m_rEngine.GetText(static_cast< ::sal_uLong >(nNumber)).Len() )
906 : static_cast< ::sal_Int32 >( aMaxPaM.GetIndex() );
907 // XXX numeric overflow (3x)
909 if ( aStartPaM > aEndPaM )
910 ::std::swap( *pBegin, *pEnd );
912 else
914 *pBegin = 0;
915 *pEnd = 0;
919 ::sal_Int32 Document::retrieveParagraphCaretPosition(ParagraphImpl const * pParagraph)
921 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
922 ::osl::MutexGuard aInternalGuard(GetMutex());
923 ::TextSelection const & rSelection = m_rView.GetSelection();
924 Paragraphs::size_type nNumber = pParagraph->getNumber();
925 TextPaM aEndPaM( rSelection.GetEnd() );
927 return aEndPaM.GetPara() == nNumber
928 ? static_cast< ::sal_Int32 >(aEndPaM.GetIndex()) : -1;
931 ::css::awt::Rectangle
932 Document::retrieveCharacterBounds(ParagraphImpl const * pParagraph,
933 ::sal_Int32 nIndex)
935 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
936 ::osl::MutexGuard aInternalGuard(GetMutex());
937 ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber());
938 sal_Int32 nLength = m_rEngine.GetText(nNumber).Len();
939 // XXX numeric overflow
940 if (nIndex < 0 || nIndex > nLength)
941 throw ::css::lang::IndexOutOfBoundsException(
942 "textwindowaccessibility.cxx:"
943 " Document::retrieveCharacterAttributes",
944 static_cast< ::css::uno::XWeak * >(this));
945 ::css::awt::Rectangle aBounds( 0, 0, 0, 0 );
946 if ( nIndex == nLength )
948 aBounds = AWTRectangle(
949 m_rEngine.PaMtoEditCursor(::TextPaM(nNumber,
950 static_cast< ::sal_uInt16 >(nIndex))));
952 else
954 ::Rectangle aLeft(
955 m_rEngine.PaMtoEditCursor(::TextPaM(nNumber,
956 static_cast< ::sal_uInt16 >(nIndex))));
957 // XXX numeric overflow
958 ::Rectangle aRight(
959 m_rEngine.PaMtoEditCursor(::TextPaM(nNumber,
960 static_cast< ::sal_uInt16 >(nIndex)
961 + 1)));
962 // XXX numeric overflow (2x)
963 // FIXME If the vertical extends of the two cursors do not match, assume
964 // nIndex is the last character on the line; the bounding box will then
965 // extend to m_rEnginge.GetMaxTextWidth():
966 ::sal_Int32 nWidth = (aLeft.Top() == aRight.Top()
967 && aLeft.Bottom() == aRight.Bottom())
968 ? static_cast< ::sal_Int32 >(aRight.Left() - aLeft.Left())
969 : static_cast< ::sal_Int32 >(m_rEngine.GetMaxTextWidth()
970 - aLeft.Left());
971 // XXX numeric overflow (4x)
972 aBounds = ::css::awt::Rectangle(static_cast< ::sal_Int32 >(aLeft.Left()),
973 static_cast< ::sal_Int32 >(aLeft.Top() - m_nViewOffset),
974 nWidth,
975 static_cast< ::sal_Int32 >(aLeft.Bottom()
976 - aLeft.Top()));
977 // XXX numeric overflow (4x)
979 return aBounds;
982 ::sal_Int32 Document::retrieveCharacterIndex(ParagraphImpl const * pParagraph,
983 ::css::awt::Point const & rPoint)
985 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
986 ::osl::MutexGuard aInternalGuard(GetMutex());
987 ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber());
988 // XXX numeric overflow
989 ::TextPaM aPaM(m_rEngine.GetPaM(::Point(static_cast< long >(rPoint.X),
990 static_cast< long >(rPoint.Y))));
991 // XXX numeric overflow (2x)
992 return aPaM.GetPara() == nNumber
993 ? static_cast< ::sal_Int32 >(aPaM.GetIndex()) : -1;
994 // XXX numeric overflow
997 ::css::uno::Sequence< ::css::beans::PropertyValue >
998 Document::retrieveCharacterAttributes(
999 ParagraphImpl const * pParagraph, ::sal_Int32 nIndex,
1000 const ::css::uno::Sequence< OUString >& aRequestedAttributes)
1002 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1003 ::osl::MutexGuard aInternalGuard(GetMutex());
1004 ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber());
1005 // XXX numeric overflow
1006 if (nIndex < 0 || nIndex >= m_rEngine.GetText(nNumber).Len())
1007 throw ::css::lang::IndexOutOfBoundsException(
1008 "textwindowaccessibility.cxx:"
1009 " Document::retrieveCharacterAttributes",
1010 static_cast< ::css::uno::XWeak * >(this));
1012 // retrieve default attributes
1013 tPropValMap aCharAttrSeq;
1014 retrieveDefaultAttributesImpl( pParagraph, aRequestedAttributes, aCharAttrSeq );
1016 // retrieve run attributes
1017 tPropValMap aRunAttrSeq;
1018 retrieveRunAttributesImpl( pParagraph, nIndex, aRequestedAttributes, aRunAttrSeq );
1020 // merge default and run attributes
1021 for ( tPropValMap::const_iterator aRunIter = aRunAttrSeq.begin();
1022 aRunIter != aRunAttrSeq.end();
1023 ++aRunIter )
1025 aCharAttrSeq[ aRunIter->first ] = aRunIter->second;
1028 return convertHashMapToSequence( aCharAttrSeq );
1031 void Document::retrieveDefaultAttributesImpl(
1032 ParagraphImpl const * pParagraph,
1033 const ::css::uno::Sequence< OUString >& RequestedAttributes,
1034 tPropValMap& rDefAttrSeq)
1036 // default attributes are not supported by text engine
1037 (void) pParagraph;
1038 (void) RequestedAttributes;
1039 (void) rDefAttrSeq;
1042 ::css::uno::Sequence< ::css::beans::PropertyValue >
1043 Document::retrieveDefaultAttributes(
1044 ParagraphImpl const * pParagraph,
1045 const ::css::uno::Sequence< OUString >& RequestedAttributes)
1047 ::osl::Guard< ::comphelper::IMutex > aExternalGuard( getExternalLock() );
1048 ::osl::MutexGuard aInternalGuard( GetMutex() );
1050 tPropValMap aDefAttrSeq;
1051 retrieveDefaultAttributesImpl( pParagraph, RequestedAttributes, aDefAttrSeq );
1052 return convertHashMapToSequence( aDefAttrSeq );
1055 // static
1056 ::css::uno::Sequence< ::css::beans::PropertyValue >
1057 Document::convertHashMapToSequence(tPropValMap& rAttrSeq)
1059 ::css::uno::Sequence< ::css::beans::PropertyValue > aValues( rAttrSeq.size() );
1060 ::css::beans::PropertyValue* pValues = aValues.getArray();
1061 ::sal_Int32 i = 0;
1062 for ( tPropValMap::const_iterator aIter = rAttrSeq.begin();
1063 aIter != rAttrSeq.end();
1064 ++aIter )
1066 pValues[i] = aIter->second;
1067 ++i;
1069 return aValues;
1072 void Document::retrieveRunAttributesImpl(
1073 ParagraphImpl const * pParagraph, ::sal_Int32 Index,
1074 const ::css::uno::Sequence< OUString >& RequestedAttributes,
1075 tPropValMap& rRunAttrSeq)
1077 ::sal_uLong nNumber = static_cast< ::sal_uLong >( pParagraph->getNumber() );
1078 ::TextPaM aPaM( nNumber, static_cast< ::sal_uInt16 >( Index ) );
1079 // XXX numeric overflow
1080 // FIXME TEXTATTR_HYPERLINK ignored:
1081 ::TextAttribFontColor const * pColor
1082 = static_cast< ::TextAttribFontColor const * >(
1083 m_rEngine.FindAttrib( aPaM, TEXTATTR_FONTCOLOR ) );
1084 ::TextAttribFontWeight const * pWeight
1085 = static_cast< ::TextAttribFontWeight const * >(
1086 m_rEngine.FindAttrib( aPaM, TEXTATTR_FONTWEIGHT ) );
1087 tPropValMap aRunAttrSeq;
1088 if ( pColor )
1090 ::css::beans::PropertyValue aPropVal;
1091 aPropVal.Name = "CharColor";
1092 aPropVal.Handle = -1;
1093 aPropVal.Value = mapFontColor( pColor->GetColor() );
1094 aPropVal.State = ::css::beans::PropertyState_DIRECT_VALUE;
1095 aRunAttrSeq[ aPropVal.Name ] = aPropVal;
1097 if ( pWeight )
1099 ::css::beans::PropertyValue aPropVal;
1100 aPropVal.Name = "CharWeight";
1101 aPropVal.Handle = -1;
1102 aPropVal.Value = mapFontWeight( pWeight->getFontWeight() );
1103 aPropVal.State = ::css::beans::PropertyState_DIRECT_VALUE;
1104 aRunAttrSeq[ aPropVal.Name ] = aPropVal;
1106 if ( RequestedAttributes.getLength() == 0 )
1108 rRunAttrSeq = aRunAttrSeq;
1110 else
1112 const OUString* pReqAttrs = RequestedAttributes.getConstArray();
1113 const ::sal_Int32 nLength = RequestedAttributes.getLength();
1114 for ( ::sal_Int32 i = 0; i < nLength; ++i )
1116 tPropValMap::iterator aIter = aRunAttrSeq.find( pReqAttrs[i] );
1117 if ( aIter != aRunAttrSeq.end() )
1119 rRunAttrSeq[ (*aIter).first ] = (*aIter).second;
1125 ::css::uno::Sequence< ::css::beans::PropertyValue >
1126 Document::retrieveRunAttributes(
1127 ParagraphImpl const * pParagraph, ::sal_Int32 Index,
1128 const ::css::uno::Sequence< OUString >& RequestedAttributes)
1130 ::osl::Guard< ::comphelper::IMutex > aExternalGuard( getExternalLock() );
1131 ::osl::MutexGuard aInternalGuard( GetMutex() );
1132 ::sal_uLong nNumber = static_cast< ::sal_uLong >( pParagraph->getNumber() );
1133 // XXX numeric overflow
1134 if ( Index < 0 || Index >= m_rEngine.GetText(nNumber).Len() )
1135 throw ::css::lang::IndexOutOfBoundsException(
1136 "textwindowaccessibility.cxx:"
1137 " Document::retrieveRunAttributes",
1138 static_cast< ::css::uno::XWeak * >( this ) );
1140 tPropValMap aRunAttrSeq;
1141 retrieveRunAttributesImpl( pParagraph, Index, RequestedAttributes, aRunAttrSeq );
1142 return convertHashMapToSequence( aRunAttrSeq );
1145 void Document::changeParagraphText(ParagraphImpl * pParagraph,
1146 OUString const & rText)
1148 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1150 ::osl::MutexGuard aInternalGuard(GetMutex());
1151 ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber());
1152 // XXX numeric overflow
1153 changeParagraphText(nNumber, 0, m_rEngine.GetTextLen(nNumber), false,
1154 false, rText);
1158 void Document::changeParagraphText(ParagraphImpl * pParagraph,
1159 ::sal_Int32 nBegin, ::sal_Int32 nEnd,
1160 bool bCut, bool bPaste,
1161 OUString const & rText)
1163 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1165 ::osl::MutexGuard aInternalGuard(GetMutex());
1166 ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber());
1167 // XXX numeric overflow
1168 if (nBegin < 0 || nBegin > nEnd
1169 || nEnd > m_rEngine.GetText(nNumber).Len())
1170 throw ::css::lang::IndexOutOfBoundsException(
1171 "textwindowaccessibility.cxx:"
1172 " Document::changeParagraphText",
1173 static_cast< ::css::uno::XWeak * >(this));
1174 changeParagraphText(nNumber, static_cast< ::sal_uInt16 >(nBegin),
1175 static_cast< ::sal_uInt16 >(nEnd), bCut, bPaste, rText);
1176 // XXX numeric overflow (2x)
1180 void Document::copyParagraphText(ParagraphImpl const * pParagraph,
1181 ::sal_Int32 nBegin, ::sal_Int32 nEnd)
1183 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1185 ::osl::MutexGuard aInternalGuard(GetMutex());
1186 ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber());
1187 // XXX numeric overflow
1188 if (nBegin < 0 || nBegin > nEnd
1189 || nEnd > m_rEngine.GetText(nNumber).Len())
1190 throw ::css::lang::IndexOutOfBoundsException(
1191 "textwindowaccessibility.cxx:"
1192 " Document::copyParagraphText",
1193 static_cast< ::css::uno::XWeak * >(this));
1194 m_rView.SetSelection(
1195 ::TextSelection(::TextPaM(nNumber, static_cast< ::sal_uInt16 >(nBegin)),
1196 ::TextPaM(nNumber, static_cast< ::sal_uInt16 >(nEnd))));
1197 // XXX numeric overflow (2x)
1198 m_rView.Copy();
1202 void Document::changeParagraphAttributes(
1203 ParagraphImpl * pParagraph, ::sal_Int32 nBegin, ::sal_Int32 nEnd,
1204 ::css::uno::Sequence< ::css::beans::PropertyValue > const & rAttributeSet)
1206 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1208 ::osl::MutexGuard aInternalGuard(GetMutex());
1209 ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber());
1210 // XXX numeric overflow
1211 if (nBegin < 0 || nBegin > nEnd
1212 || nEnd > m_rEngine.GetText(nNumber).Len())
1213 throw ::css::lang::IndexOutOfBoundsException(
1214 "textwindowaccessibility.cxx:"
1215 " Document::changeParagraphAttributes",
1216 static_cast< ::css::uno::XWeak * >(this));
1218 // FIXME The new attributes are added to any attributes already set,
1219 // they do not replace the old attributes as required by
1220 // XAccessibleEditableText.setAttributes:
1221 for (::sal_Int32 i = 0; i < rAttributeSet.getLength(); ++i)
1222 if ( rAttributeSet[i].Name == "CharColor" )
1223 m_rEngine.SetAttrib(::TextAttribFontColor(
1224 mapFontColor(rAttributeSet[i].Value)),
1225 nNumber, static_cast< ::sal_uInt16 >(nBegin),
1226 static_cast< ::sal_uInt16 >(nEnd));
1227 // XXX numeric overflow (2x)
1228 else if ( rAttributeSet[i].Name == "CharWeight" )
1229 m_rEngine.SetAttrib(::TextAttribFontWeight(
1230 mapFontWeight(rAttributeSet[i].Value)),
1231 nNumber, static_cast< ::sal_uInt16 >(nBegin),
1232 static_cast< ::sal_uInt16 >(nEnd));
1233 // XXX numeric overflow (2x)
1237 void Document::changeParagraphSelection(ParagraphImpl * pParagraph,
1238 ::sal_Int32 nBegin, ::sal_Int32 nEnd)
1240 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1242 ::osl::MutexGuard aInternalGuard(GetMutex());
1243 ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber());
1244 // XXX numeric overflow
1245 if (nBegin < 0 || nBegin > nEnd
1246 || nEnd > m_rEngine.GetText(nNumber).Len())
1247 throw ::css::lang::IndexOutOfBoundsException(
1248 "textwindowaccessibility.cxx:"
1249 " Document::changeParagraphSelection",
1250 static_cast< ::css::uno::XWeak * >(this));
1251 m_rView.SetSelection(
1252 ::TextSelection(::TextPaM(nNumber, static_cast< ::sal_uInt16 >(nBegin)),
1253 ::TextPaM(nNumber, static_cast< ::sal_uInt16 >(nEnd))));
1254 // XXX numeric overflow (2x)
1258 ::css::i18n::Boundary
1259 Document::retrieveParagraphLineBoundary( ParagraphImpl const * pParagraph,
1260 ::sal_Int32 nIndex, ::sal_Int32 *pLineNo )
1262 ::css::i18n::Boundary aBoundary;
1263 aBoundary.startPos = nIndex;
1264 aBoundary.endPos = nIndex;
1266 ::osl::Guard< ::comphelper::IMutex > aExternalGuard( getExternalLock() );
1268 ::osl::MutexGuard aInternalGuard( GetMutex() );
1269 ::sal_uLong nNumber = static_cast< ::sal_uLong >( pParagraph->getNumber() );
1270 if ( nIndex < 0 || nIndex > m_rEngine.GetText( nNumber ).Len() )
1271 throw ::css::lang::IndexOutOfBoundsException(
1272 "textwindowaccessibility.cxx:"
1273 " Document::retrieveParagraphLineBoundary",
1274 static_cast< ::css::uno::XWeak * >( this ) );
1275 ::sal_Int32 nLineStart = 0;
1276 ::sal_Int32 nLineEnd = 0;
1277 ::sal_uInt16 nLineCount = m_rEngine.GetLineCount( nNumber );
1278 for ( ::sal_uInt16 nLine = 0; nLine < nLineCount; ++nLine )
1280 ::sal_Int32 nLineLength = static_cast< ::sal_Int32 >(
1281 m_rEngine.GetLineLen( nNumber, nLine ) );
1282 nLineStart = nLineEnd;
1283 nLineEnd += nLineLength;
1284 if ( nIndex >= nLineStart && ( ( nLine == nLineCount - 1 ) ? nIndex <= nLineEnd : nIndex < nLineEnd ) )
1286 aBoundary.startPos = nLineStart;
1287 aBoundary.endPos = nLineEnd;
1288 if( pLineNo )
1289 pLineNo[0] = nLine;
1290 break;
1295 return aBoundary;
1298 ::css::i18n::Boundary
1299 Document::retrieveParagraphBoundaryOfLine( ParagraphImpl const * pParagraph,
1300 ::sal_Int32 nLineNo )
1302 ::css::i18n::Boundary aBoundary;
1303 aBoundary.startPos = 0;
1304 aBoundary.endPos = 0;
1306 ::osl::Guard< ::comphelper::IMutex > aExternalGuard( getExternalLock() );
1308 ::osl::MutexGuard aInternalGuard( GetMutex() );
1309 ::sal_uLong nNumber = static_cast< ::sal_uLong >( pParagraph->getNumber() );
1310 if ( nLineNo >= m_rEngine.GetLineCount( nNumber ) )
1311 throw ::css::lang::IndexOutOfBoundsException(
1312 "textwindowaccessibility.cxx:"
1313 " Document::retrieveParagraphBoundaryOfLine",
1314 static_cast< ::css::uno::XWeak * >( this ) );
1315 ::sal_Int32 nLineStart = 0;
1316 ::sal_Int32 nLineEnd = 0;
1317 for ( ::sal_uInt16 nLine = 0; nLine <= nLineNo; ++nLine )
1319 ::sal_Int32 nLineLength = static_cast< ::sal_Int32 >(
1320 m_rEngine.GetLineLen( nNumber, nLine ) );
1321 nLineStart = nLineEnd;
1322 nLineEnd += nLineLength;
1325 aBoundary.startPos = nLineStart;
1326 aBoundary.endPos = nLineEnd;
1329 return aBoundary;
1332 sal_Int32 Document::retrieveParagraphLineWithCursor( ParagraphImpl const * pParagraph )
1334 ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1335 ::osl::MutexGuard aInternalGuard(GetMutex());
1336 ::TextSelection const & rSelection = m_rView.GetSelection();
1337 Paragraphs::size_type nNumber = pParagraph->getNumber();
1338 TextPaM aEndPaM( rSelection.GetEnd() );
1340 return aEndPaM.GetPara() == nNumber
1341 ? m_rView.GetLineNumberOfCursorInSelection() : -1;
1345 ::css::uno::Reference< ::css::accessibility::XAccessibleRelationSet >
1346 Document::retrieveParagraphRelationSet( ParagraphImpl const * pParagraph )
1348 ::osl::MutexGuard aInternalGuard( GetMutex() );
1350 ::utl::AccessibleRelationSetHelper* pRelationSetHelper = new ::utl::AccessibleRelationSetHelper();
1351 ::css::uno::Reference< ::css::accessibility::XAccessibleRelationSet > xSet = pRelationSetHelper;
1353 Paragraphs::iterator aPara( m_xParagraphs->begin() + pParagraph->getNumber() );
1355 if ( aPara > m_aVisibleBegin && aPara < m_aVisibleEnd )
1357 ::css::uno::Sequence< ::css::uno::Reference< ::css::uno::XInterface > > aSequence(1);
1358 aSequence[0] = getAccessibleChild( aPara - 1 );
1359 ::css::accessibility::AccessibleRelation aRelation( ::css::accessibility::AccessibleRelationType::CONTENT_FLOWS_FROM, aSequence );
1360 pRelationSetHelper->AddRelation( aRelation );
1363 if ( aPara >= m_aVisibleBegin && aPara < m_aVisibleEnd -1 )
1365 ::css::uno::Sequence< ::css::uno::Reference< ::css::uno::XInterface > > aSequence(1);
1366 aSequence[0] = getAccessibleChild( aPara + 1 );
1367 ::css::accessibility::AccessibleRelation aRelation( ::css::accessibility::AccessibleRelationType::CONTENT_FLOWS_TO, aSequence );
1368 pRelationSetHelper->AddRelation( aRelation );
1371 return xSet;
1374 void Document::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent )
1376 switch ( rVclWindowEvent.GetId() )
1378 case VCLEVENT_WINDOW_GETFOCUS:
1379 case VCLEVENT_WINDOW_LOSEFOCUS:
1381 // #107179# if our parent is a compound control (e.g. MultiLineEdit),
1382 // suppress the window focus events here
1383 if ( !m_bCompoundControlChild )
1384 VCLXAccessibleComponent::ProcessWindowEvent( rVclWindowEvent );
1386 break;
1387 default:
1388 VCLXAccessibleComponent::ProcessWindowEvent( rVclWindowEvent );
1392 // virtual
1393 ::sal_Int32 SAL_CALL Document::getAccessibleChildCount()
1394 throw (::css::uno::RuntimeException)
1396 ::comphelper::OExternalLockGuard aGuard(this);
1397 init();
1398 return m_aVisibleEnd - m_aVisibleBegin;
1401 // virtual
1402 ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL
1403 Document::getAccessibleChild(::sal_Int32 i)
1404 throw (::css::lang::IndexOutOfBoundsException,
1405 ::css::uno::RuntimeException)
1407 ::comphelper::OExternalLockGuard aGuard(this);
1408 init();
1409 if (i < 0 || i >= m_aVisibleEnd - m_aVisibleBegin)
1410 throw ::css::lang::IndexOutOfBoundsException(
1411 "textwindowaccessibility.cxx:"
1412 " Document::getAccessibleChild",
1413 static_cast< ::css::uno::XWeak * >(this));
1414 return getAccessibleChild(m_aVisibleBegin
1415 + static_cast< Paragraphs::size_type >(i));
1418 // virtual
1419 ::sal_Int16 SAL_CALL Document::getAccessibleRole()
1420 throw (::css::uno::RuntimeException)
1422 return ::css::accessibility::AccessibleRole::TEXT_FRAME;
1425 // virtual
1426 ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL
1427 Document::getAccessibleAtPoint(::css::awt::Point const & rPoint)
1428 throw (::css::uno::RuntimeException)
1430 ::comphelper::OExternalLockGuard aGuard(this);
1431 init();
1432 if (rPoint.X >= 0
1433 && rPoint.X < m_rView.GetWindow()->GetOutputSizePixel().Width()
1434 && rPoint.Y >= 0 && rPoint.Y < m_nViewHeight)
1436 ::sal_Int32 nOffset = m_nViewOffset + rPoint.Y; // XXX numeric overflow
1437 ::sal_Int32 nPos = m_nViewOffset - m_nVisibleBeginOffset;
1438 for (Paragraphs::iterator aIt(m_aVisibleBegin); aIt != m_aVisibleEnd;
1439 ++aIt)
1441 nPos += aIt->getHeight(); // XXX numeric overflow
1442 if (nOffset < nPos)
1443 return getAccessibleChild(aIt);
1446 return 0;
1449 // virtual
1450 void SAL_CALL Document::disposing()
1452 m_aEngineListener.endListening();
1453 m_aViewListener.endListening();
1454 if (m_xParagraphs.get() != 0)
1455 disposeParagraphs();
1456 VCLXAccessibleComponent::disposing();
1459 // virtual
1460 void Document::Notify(::SfxBroadcaster &, ::SfxHint const & rHint)
1462 if (rHint.ISA(::TextHint))
1464 ::TextHint const & rTextHint
1465 = static_cast< ::TextHint const & >(rHint);
1466 switch (rTextHint.GetId())
1468 case TEXT_HINT_PARAINSERTED:
1469 case TEXT_HINT_PARAREMOVED:
1470 // TEXT_HINT_PARAINSERTED and TEXT_HINT_PARAREMOVED are sent at
1471 // "unsafe" times (when the text engine has not yet re-formatted its
1472 // content), so that for example calling ::TextEngine::GetTextHeight
1473 // from within the code that handles TEXT_HINT_PARAINSERTED causes
1474 // trouble within the text engine. Therefore, these hints are just
1475 // buffered until a following ::TextEngine::FormatDoc causes a
1476 // TEXT_HINT_TEXTFORMATTED to come in:
1477 case TEXT_HINT_FORMATPARA:
1478 // ::TextEngine::FormatDoc sends a sequence of
1479 // TEXT_HINT_FORMATPARAs, followed by an optional
1480 // TEXT_HINT_TEXTHEIGHTCHANGED, followed in all cases by one
1481 // TEXT_HINT_TEXTFORMATTED. Only the TEXT_HINT_FORMATPARAs contain
1482 // the the numbers of the affected paragraphs, but they are sent
1483 // before the changes are applied. Therefore, TEXT_HINT_FORMATPARAs
1484 // are just buffered until another hint comes in:
1486 ::osl::MutexGuard aInternalGuard(GetMutex());
1487 if (!isAlive())
1488 break;
1490 m_aParagraphNotifications.push(rTextHint);
1491 break;
1493 case TEXT_HINT_TEXTFORMATTED:
1494 case TEXT_HINT_TEXTHEIGHTCHANGED:
1495 case TEXT_HINT_MODIFIED:
1497 ::osl::MutexGuard aInternalGuard(GetMutex());
1498 if (!isAlive())
1499 break;
1500 handleParagraphNotifications();
1501 break;
1503 case TEXT_HINT_VIEWSCROLLED:
1505 ::osl::MutexGuard aInternalGuard(GetMutex());
1506 if (!isAlive())
1507 break;
1508 handleParagraphNotifications();
1510 ::sal_Int32 nOffset = static_cast< ::sal_Int32 >(
1511 m_rView.GetStartDocPos().Y());
1512 // XXX numeric overflow
1513 if (nOffset != m_nViewOffset)
1515 m_nViewOffset = nOffset;
1517 Paragraphs::iterator aOldVisibleBegin(
1518 m_aVisibleBegin);
1519 Paragraphs::iterator aOldVisibleEnd(m_aVisibleEnd);
1521 determineVisibleRange();
1523 notifyVisibleRangeChanges(aOldVisibleBegin,
1524 aOldVisibleEnd,
1525 m_xParagraphs->end());
1527 break;
1529 case TEXT_HINT_VIEWSELECTIONCHANGED:
1531 ::osl::MutexGuard aInternalGuard(GetMutex());
1532 if (!isAlive())
1533 break;
1535 if (m_aParagraphNotifications.empty())
1537 handleSelectionChangeNotification();
1539 else
1541 // TEXT_HINT_VIEWSELECTIONCHANGED is sometimes sent at
1542 // "unsafe" times (when the text engine has not yet re-
1543 // formatted its content), so that for example calling
1544 // ::TextEngine::GetTextHeight from within the code that
1545 // handles a previous TEXT_HINT_PARAINSERTED causes
1546 // trouble within the text engine. Therefore, these
1547 // hints are just buffered (along with
1548 // TEXT_HINT_PARAINSERTED/REMOVED/FORMATPARA) until a
1549 // following ::TextEngine::FormatDoc causes a
1550 // TEXT_HINT_TEXTFORMATTED to come in:
1551 m_bSelectionChangedNotification = true;
1553 break;
1559 IMPL_LINK(Document, WindowEventHandler, ::VclSimpleEvent *, pEvent)
1561 switch (pEvent->GetId())
1563 case VCLEVENT_WINDOW_RESIZE:
1565 ::osl::MutexGuard aInternalGuard(GetMutex());
1566 if (!isAlive())
1567 break;
1569 ::sal_Int32 nHeight = static_cast< ::sal_Int32 >(
1570 m_rView.GetWindow()->GetOutputSizePixel().Height());
1571 // XXX numeric overflow
1572 if (nHeight != m_nViewHeight)
1574 m_nViewHeight = nHeight;
1576 Paragraphs::iterator aOldVisibleBegin(m_aVisibleBegin);
1577 Paragraphs::iterator aOldVisibleEnd(m_aVisibleEnd);
1579 determineVisibleRange();
1581 notifyVisibleRangeChanges(aOldVisibleBegin, aOldVisibleEnd,
1582 m_xParagraphs->end());
1584 break;
1586 case VCLEVENT_WINDOW_GETFOCUS:
1588 ::osl::MutexGuard aInternalGuard(GetMutex());
1589 if (!isAlive())
1590 break;
1592 if (m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd)
1594 ::rtl::Reference< ParagraphImpl > xParagraph(
1595 getParagraph(m_aFocused));
1596 if (xParagraph.is())
1597 xParagraph->notifyEvent(
1598 ::css::accessibility::AccessibleEventId::
1599 STATE_CHANGED,
1600 ::css::uno::Any(),
1601 ::css::uno::makeAny(
1602 ::css::accessibility::AccessibleStateType::
1603 FOCUSED));
1605 break;
1607 case VCLEVENT_WINDOW_LOSEFOCUS:
1609 ::osl::MutexGuard aInternalGuard(GetMutex());
1610 if (!isAlive())
1611 break;
1613 if (m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd)
1615 ::rtl::Reference< ParagraphImpl > xParagraph(
1616 getParagraph(m_aFocused));
1617 if (xParagraph.is())
1618 xParagraph->notifyEvent(
1619 ::css::accessibility::AccessibleEventId::
1620 STATE_CHANGED,
1621 ::css::uno::makeAny(
1622 ::css::accessibility::AccessibleStateType::
1623 FOCUSED),
1624 ::css::uno::Any());
1626 break;
1629 return 0;
1632 void Document::init()
1634 if (m_xParagraphs.get() == 0)
1636 ::sal_uLong nCount = m_rEngine.GetParagraphCount();
1637 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1638 ::std::auto_ptr< Paragraphs > p(new Paragraphs);
1639 SAL_WNODEPRECATED_DECLARATIONS_POP
1640 p->reserve(static_cast< Paragraphs::size_type >(nCount));
1641 // numeric overflow is harmless here
1642 for (::sal_uLong i = 0; i < nCount; ++i)
1643 p->push_back(ParagraphInfo(static_cast< ::sal_Int32 >(
1644 m_rEngine.GetTextHeight(i))));
1645 // XXX numeric overflow
1646 m_nViewOffset = static_cast< ::sal_Int32 >(
1647 m_rView.GetStartDocPos().Y()); // XXX numeric overflow
1648 m_nViewHeight = static_cast< ::sal_Int32 >(
1649 m_rView.GetWindow()->GetOutputSizePixel().Height());
1650 // XXX numeric overflow
1651 m_xParagraphs = p;
1652 determineVisibleRange();
1653 m_nSelectionFirstPara = -1;
1654 m_nSelectionFirstPos = -1;
1655 m_nSelectionLastPara = -1;
1656 m_nSelectionLastPos = -1;
1657 m_aFocused = m_xParagraphs->end();
1658 m_bSelectionChangedNotification = false;
1659 m_aEngineListener.startListening(m_rEngine);
1660 m_aViewListener.startListening(*m_rView.GetWindow());
1664 ::rtl::Reference< ParagraphImpl >
1665 Document::getParagraph(Paragraphs::iterator const & rIt)
1667 return static_cast< ParagraphImpl * >(
1668 ::css::uno::Reference< ::css::accessibility::XAccessible >(
1669 rIt->getParagraph()).get());
1672 ::css::uno::Reference< ::css::accessibility::XAccessible >
1673 Document::getAccessibleChild(Paragraphs::iterator const & rIt)
1675 ::css::uno::Reference< ::css::accessibility::XAccessible > xParagraph(
1676 rIt->getParagraph());
1677 if (!xParagraph.is())
1679 xParagraph = new Paragraph(this, rIt - m_xParagraphs->begin());
1680 rIt->setParagraph(xParagraph);
1682 return xParagraph;
1685 void Document::determineVisibleRange()
1687 Paragraphs::iterator const aEnd = m_xParagraphs->end();
1689 m_aVisibleBegin = aEnd;
1690 m_aVisibleEnd = aEnd;
1691 m_nVisibleBeginOffset = 0;
1693 ::sal_Int32 nPos = 0;
1694 for (Paragraphs::iterator aIt = m_xParagraphs->begin(); m_aVisibleEnd == aEnd && aIt != aEnd; ++aIt)
1696 ::sal_Int32 const nOldPos = nPos;
1697 nPos += aIt->getHeight(); // XXX numeric overflow
1698 if (m_aVisibleBegin == aEnd)
1700 if (nPos >= m_nViewOffset)
1702 m_aVisibleBegin = aIt;
1703 m_nVisibleBeginOffset = m_nViewOffset - nOldPos;
1706 else
1708 if (nPos >= m_nViewOffset + m_nViewHeight) // XXX numeric overflow
1710 m_aVisibleEnd = aIt;
1715 OSL_POSTCOND(
1716 (m_aVisibleBegin == m_xParagraphs->end() && m_aVisibleEnd == m_xParagraphs->end() && m_nVisibleBeginOffset == 0)
1717 || (m_aVisibleBegin < m_aVisibleEnd && m_nVisibleBeginOffset >= 0),
1718 "invalid visible range");
1721 void Document::notifyVisibleRangeChanges(
1722 Paragraphs::iterator const & rOldVisibleBegin,
1723 Paragraphs::iterator const & rOldVisibleEnd,
1724 Paragraphs::iterator const & rInserted)
1726 // XXX Replace this code that determines which paragraphs have changed from
1727 // invisible to visible or vice versa with a better algorithm.
1728 {for (Paragraphs::iterator aIt(rOldVisibleBegin); aIt != rOldVisibleEnd;
1729 ++aIt)
1730 if (aIt != rInserted
1731 && (aIt < m_aVisibleBegin || aIt >= m_aVisibleEnd))
1732 NotifyAccessibleEvent(
1733 ::css::accessibility::AccessibleEventId::
1734 CHILD,
1735 ::css::uno::makeAny(getAccessibleChild(aIt)),
1736 ::css::uno::Any());
1738 {for (Paragraphs::iterator aIt(m_aVisibleBegin); aIt != m_aVisibleEnd;
1739 ++aIt)
1740 if (aIt == rInserted
1741 || aIt < rOldVisibleBegin || aIt >= rOldVisibleEnd)
1742 NotifyAccessibleEvent(
1743 ::css::accessibility::AccessibleEventId::
1744 CHILD,
1745 ::css::uno::Any(),
1746 ::css::uno::makeAny(getAccessibleChild(aIt)));
1750 void
1751 Document::changeParagraphText(::sal_uLong nNumber, ::sal_uInt16 nBegin, ::sal_uInt16 nEnd,
1752 bool bCut, bool bPaste,
1753 OUString const & rText)
1755 m_rView.SetSelection(::TextSelection(::TextPaM(nNumber, nBegin),
1756 ::TextPaM(nNumber, nEnd)));
1757 if (bCut)
1758 m_rView.Cut();
1759 else if (nBegin != nEnd)
1760 m_rView.DeleteSelected();
1761 if (bPaste)
1762 m_rView.Paste();
1763 else if (!rText.isEmpty())
1764 m_rView.InsertText(rText);
1767 void Document::handleParagraphNotifications()
1769 while (!m_aParagraphNotifications.empty())
1771 ::TextHint aHint(m_aParagraphNotifications.front());
1772 m_aParagraphNotifications.pop();
1773 switch (aHint.GetId())
1775 case TEXT_HINT_PARAINSERTED:
1777 ::sal_uLong n = aHint.GetValue();
1778 OSL_ENSURE(n <= m_xParagraphs->size(),
1779 "bad TEXT_HINT_PARAINSERTED event");
1781 // Save the values of old iterators (the iterators themselves
1782 // will get invalidated), and adjust the old values so that they
1783 // reflect the insertion of the new paragraph:
1784 Paragraphs::size_type nOldVisibleBegin
1785 = m_aVisibleBegin - m_xParagraphs->begin();
1786 Paragraphs::size_type nOldVisibleEnd
1787 = m_aVisibleEnd - m_xParagraphs->begin();
1788 Paragraphs::size_type nOldFocused
1789 = m_aFocused - m_xParagraphs->begin();
1790 if (n <= nOldVisibleBegin)
1791 ++nOldVisibleBegin; // XXX numeric overflow
1792 if (n <= nOldVisibleEnd)
1793 ++nOldVisibleEnd; // XXX numeric overflow
1794 if (n <= nOldFocused)
1795 ++nOldFocused; // XXX numeric overflow
1796 if (sal::static_int_cast<sal_Int32>(n) <= m_nSelectionFirstPara)
1797 ++m_nSelectionFirstPara; // XXX numeric overflow
1798 if (sal::static_int_cast<sal_Int32>(n) <= m_nSelectionLastPara)
1799 ++m_nSelectionLastPara; // XXX numeric overflow
1801 Paragraphs::iterator aIns(
1802 m_xParagraphs->insert(
1803 m_xParagraphs->begin() + n,
1804 ParagraphInfo(static_cast< ::sal_Int32 >(
1805 m_rEngine.GetTextHeight(n)))));
1806 // XXX numeric overflow (2x)
1808 determineVisibleRange();
1809 m_aFocused = m_xParagraphs->begin() + nOldFocused;
1811 for (Paragraphs::iterator aIt(aIns);;)
1813 ++aIt;
1814 if (aIt == m_xParagraphs->end())
1815 break;
1816 ::rtl::Reference< ParagraphImpl > xParagraph(
1817 getParagraph(aIt));
1818 if (xParagraph.is())
1819 xParagraph->numberChanged(true);
1822 notifyVisibleRangeChanges(
1823 m_xParagraphs->begin() + nOldVisibleBegin,
1824 m_xParagraphs->begin() + nOldVisibleEnd, aIns);
1825 break;
1827 case TEXT_HINT_PARAREMOVED:
1829 ::sal_uLong n = aHint.GetValue();
1830 if (n == TEXT_PARA_ALL)
1832 {for (Paragraphs::iterator aIt(m_aVisibleBegin);
1833 aIt != m_aVisibleEnd; ++aIt)
1834 NotifyAccessibleEvent(
1835 ::css::accessibility::AccessibleEventId::
1836 CHILD,
1837 ::css::uno::makeAny(getAccessibleChild(aIt)),
1838 ::css::uno::Any());
1840 disposeParagraphs();
1841 m_xParagraphs->clear();
1842 determineVisibleRange();
1843 m_nSelectionFirstPara = -1;
1844 m_nSelectionFirstPos = -1;
1845 m_nSelectionLastPara = -1;
1846 m_nSelectionLastPos = -1;
1847 m_aFocused = m_xParagraphs->end();
1849 else
1851 OSL_ENSURE(n < m_xParagraphs->size(),
1852 "Bad TEXT_HINT_PARAREMOVED event");
1854 Paragraphs::iterator aIt(m_xParagraphs->begin() + n);
1855 // numeric overflow cannot occur
1857 // Save the values of old iterators (the iterators
1858 // themselves will get invalidated), and adjust the old
1859 // values so that they reflect the removal of the paragraph:
1860 Paragraphs::size_type nOldVisibleBegin
1861 = m_aVisibleBegin - m_xParagraphs->begin();
1862 Paragraphs::size_type nOldVisibleEnd
1863 = m_aVisibleEnd - m_xParagraphs->begin();
1864 bool bWasVisible
1865 = nOldVisibleBegin <= n && n < nOldVisibleEnd;
1866 Paragraphs::size_type nOldFocused
1867 = m_aFocused - m_xParagraphs->begin();
1868 bool bWasFocused = aIt == m_aFocused;
1869 if (n < nOldVisibleBegin)
1870 --nOldVisibleBegin;
1871 if (n < nOldVisibleEnd)
1872 --nOldVisibleEnd;
1873 if (n < nOldFocused)
1874 --nOldFocused;
1875 if (sal::static_int_cast<sal_Int32>(n) < m_nSelectionFirstPara)
1876 --m_nSelectionFirstPara;
1877 else if (sal::static_int_cast<sal_Int32>(n) == m_nSelectionFirstPara)
1879 if (m_nSelectionFirstPara == m_nSelectionLastPara)
1881 m_nSelectionFirstPara = -1;
1882 m_nSelectionFirstPos = -1;
1883 m_nSelectionLastPara = -1;
1884 m_nSelectionLastPos = -1;
1886 else
1888 ++m_nSelectionFirstPara;
1889 m_nSelectionFirstPos = 0;
1892 if (sal::static_int_cast<sal_Int32>(n) < m_nSelectionLastPara)
1893 --m_nSelectionLastPara;
1894 else if (sal::static_int_cast<sal_Int32>(n) == m_nSelectionLastPara)
1896 OSL_ENSURE(m_nSelectionFirstPara < m_nSelectionLastPara,
1897 "logic error");
1898 --m_nSelectionLastPara;
1899 m_nSelectionLastPos = 0x7FFFFFFF;
1902 ::css::uno::Reference< ::css::accessibility::XAccessible >
1903 xStrong;
1904 if (bWasVisible)
1905 xStrong = getAccessibleChild(aIt);
1906 ::css::uno::WeakReference<
1907 ::css::accessibility::XAccessible > xWeak(
1908 aIt->getParagraph());
1909 aIt = m_xParagraphs->erase(aIt);
1911 determineVisibleRange();
1912 m_aFocused = bWasFocused ? m_xParagraphs->end()
1913 : m_xParagraphs->begin() + nOldFocused;
1915 for (; aIt != m_xParagraphs->end(); ++aIt)
1917 ::rtl::Reference< ParagraphImpl > xParagraph(
1918 getParagraph(aIt));
1919 if (xParagraph.is())
1920 xParagraph->numberChanged(false);
1923 if (bWasVisible)
1924 NotifyAccessibleEvent(
1925 ::css::accessibility::AccessibleEventId::
1926 CHILD,
1927 ::css::uno::makeAny(xStrong),
1928 ::css::uno::Any());
1930 ::css::uno::Reference< ::css::lang::XComponent > xComponent(
1931 xWeak.get(), ::css::uno::UNO_QUERY);
1932 if (xComponent.is())
1933 xComponent->dispose();
1935 notifyVisibleRangeChanges(
1936 m_xParagraphs->begin() + nOldVisibleBegin,
1937 m_xParagraphs->begin() + nOldVisibleEnd,
1938 m_xParagraphs->end());
1940 break;
1942 case TEXT_HINT_FORMATPARA:
1944 ::sal_uLong n = aHint.GetValue();
1945 OSL_ENSURE(n < m_xParagraphs->size(),
1946 "Bad TEXT_HINT_FORMATPARA event");
1948 (*m_xParagraphs)[static_cast< Paragraphs::size_type >(n)].
1949 changeHeight(static_cast< ::sal_Int32 >(
1950 m_rEngine.GetTextHeight(n)));
1951 // XXX numeric overflow
1952 Paragraphs::iterator aOldVisibleBegin(m_aVisibleBegin);
1953 Paragraphs::iterator aOldVisibleEnd(m_aVisibleEnd);
1954 determineVisibleRange();
1955 notifyVisibleRangeChanges(aOldVisibleBegin, aOldVisibleEnd,
1956 m_xParagraphs->end());
1958 if (n < m_xParagraphs->size())
1960 Paragraphs::iterator aIt(m_xParagraphs->begin() + n);
1961 ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(aIt));
1962 if (xParagraph.is())
1963 xParagraph->textChanged();
1965 break;
1967 default:
1968 OSL_FAIL( "bad buffered hint");
1969 break;
1972 if (m_bSelectionChangedNotification)
1974 m_bSelectionChangedNotification = false;
1975 handleSelectionChangeNotification();
1979 void Document::handleSelectionChangeNotification()
1981 ::TextSelection const & rSelection = m_rView.GetSelection();
1982 OSL_ENSURE(rSelection.GetStart().GetPara() < m_xParagraphs->size()
1983 && rSelection.GetEnd().GetPara() < m_xParagraphs->size(),
1984 "bad TEXT_HINT_VIEWSELECTIONCHANGED event");
1985 ::sal_Int32 nNewFirstPara
1986 = static_cast< ::sal_Int32 >(rSelection.GetStart().GetPara());
1987 ::sal_Int32 nNewFirstPos
1988 = static_cast< ::sal_Int32 >(rSelection.GetStart().GetIndex());
1989 // XXX numeric overflow
1990 ::sal_Int32 nNewLastPara
1991 = static_cast< ::sal_Int32 >(rSelection.GetEnd().GetPara());
1992 ::sal_Int32 nNewLastPos
1993 = static_cast< ::sal_Int32 >(rSelection.GetEnd().GetIndex());
1994 // XXX numeric overflow
1996 // Lose focus:
1997 Paragraphs::iterator aIt(m_xParagraphs->begin() + nNewLastPara);
1998 if (m_aFocused != m_xParagraphs->end() && m_aFocused != aIt
1999 && m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd)
2001 ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(m_aFocused));
2002 if (xParagraph.is())
2003 xParagraph->notifyEvent(
2004 ::css::accessibility::AccessibleEventId::
2005 STATE_CHANGED,
2006 ::css::uno::makeAny(
2007 ::css::accessibility::AccessibleStateType::FOCUSED),
2008 ::css::uno::Any());
2011 // Gain focus and update cursor position:
2012 if (aIt >= m_aVisibleBegin && aIt < m_aVisibleEnd
2013 && (aIt != m_aFocused
2014 || nNewLastPara != m_nSelectionLastPara
2015 || nNewLastPos != m_nSelectionLastPos))
2017 ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(aIt));
2018 if (xParagraph.is())
2020 if (aIt != m_aFocused)
2021 xParagraph->notifyEvent(
2022 ::css::accessibility::AccessibleEventId::
2023 STATE_CHANGED,
2024 ::css::uno::Any(),
2025 ::css::uno::makeAny(
2026 ::css::accessibility::AccessibleStateType::FOCUSED));
2027 if (nNewLastPara != m_nSelectionLastPara
2028 || nNewLastPos != m_nSelectionLastPos)
2029 xParagraph->notifyEvent(
2030 ::css::accessibility::AccessibleEventId::
2031 CARET_CHANGED,
2032 ::css::uno::makeAny< ::sal_Int32 >(
2033 nNewLastPara == m_nSelectionLastPara
2034 ? m_nSelectionLastPos : 0),
2035 ::css::uno::makeAny(nNewLastPos));
2038 m_aFocused = aIt;
2040 // Update both old and new selection. (Regardless of how the two selections
2041 // look like, there will always be two ranges to the left and right of the
2042 // overlap---the overlap and/or the range to the right of it possibly being
2043 // empty. Only for these two ranges notifications have to be sent.)
2045 TextPaM aOldTextStart( static_cast< sal_uLong >( m_nSelectionFirstPara ), static_cast< sal_uInt16 >( m_nSelectionFirstPos ) );
2046 TextPaM aOldTextEnd( static_cast< sal_uLong >( m_nSelectionLastPara ), static_cast< sal_uInt16 >( m_nSelectionLastPos ) );
2047 TextPaM aNewTextStart( static_cast< sal_uLong >( nNewFirstPara ), static_cast< sal_uInt16 >( nNewFirstPos ) );
2048 TextPaM aNewTextEnd( static_cast< sal_uLong >( nNewLastPara ), static_cast< sal_uInt16 >( nNewLastPos ) );
2050 // justify selections
2051 justifySelection( aOldTextStart, aOldTextEnd );
2052 justifySelection( aNewTextStart, aNewTextEnd );
2054 sal_Int32 nFirst1;
2055 sal_Int32 nLast1;
2056 sal_Int32 nFirst2;
2057 sal_Int32 nLast2;
2059 if ( m_nSelectionFirstPara == -1 )
2061 // old selection not initialized yet => notify events only for new selection (if not empty)
2062 nFirst1 = aNewTextStart.GetPara();
2063 nLast1 = aNewTextEnd.GetPara() + ( aNewTextStart != aNewTextEnd ? 1 : 0 );
2064 nFirst2 = 0;
2065 nLast2 = 0;
2067 else if ( aOldTextStart == aOldTextEnd && aNewTextStart == aNewTextEnd )
2069 // old and new selection empty => no events
2070 nFirst1 = 0;
2071 nLast1 = 0;
2072 nFirst2 = 0;
2073 nLast2 = 0;
2075 else if ( aOldTextStart != aOldTextEnd && aNewTextStart == aNewTextEnd )
2077 // old selection not empty + new selection empty => notify events only for old selection
2078 nFirst1 = aOldTextStart.GetPara();
2079 nLast1 = aOldTextEnd.GetPara() + 1;
2080 nFirst2 = 0;
2081 nLast2 = 0;
2083 else if ( aOldTextStart == aOldTextEnd && aNewTextStart != aNewTextEnd )
2085 // old selection empty + new selection not empty => notify events only for new selection
2086 nFirst1 = aNewTextStart.GetPara();
2087 nLast1 = aNewTextEnd.GetPara() + 1;
2088 nFirst2 = 0;
2089 nLast2 = 0;
2091 else
2093 // old and new selection not empty => notify events for the two ranges left and right of the overlap
2094 ::std::vector< TextPaM > aTextPaMs(4);
2095 aTextPaMs[0] = aOldTextStart;
2096 aTextPaMs[1] = aOldTextEnd;
2097 aTextPaMs[2] = aNewTextStart;
2098 aTextPaMs[3] = aNewTextEnd;
2099 ::std::sort( aTextPaMs.begin(), aTextPaMs.end() );
2101 nFirst1 = aTextPaMs[0].GetPara();
2102 nLast1 = aTextPaMs[1].GetPara() + ( aTextPaMs[0] != aTextPaMs[1] ? 1 : 0 );
2104 nFirst2 = aTextPaMs[2].GetPara();
2105 nLast2 = aTextPaMs[3].GetPara() + ( aTextPaMs[2] != aTextPaMs[3] ? 1 : 0 );
2107 // adjust overlapping ranges
2108 if ( nLast1 > nFirst2 )
2109 nLast1 = nFirst2;
2112 // notify selection changes
2113 notifySelectionChange( nFirst1, nLast1 );
2114 notifySelectionChange( nFirst2, nLast2 );
2116 m_nSelectionFirstPara = nNewFirstPara;
2117 m_nSelectionFirstPos = nNewFirstPos;
2118 m_nSelectionLastPara = nNewLastPara;
2119 m_nSelectionLastPos = nNewLastPos;
2122 void Document::notifySelectionChange( sal_Int32 nFirst, sal_Int32 nLast )
2124 nFirst = std::max( nFirst, sal_Int32( 0 ) );
2125 nLast = std::min( nLast, sal_Int32( m_xParagraphs->size() ) );
2126 Paragraphs::iterator iFirst(m_xParagraphs->begin() + nFirst);
2127 Paragraphs::iterator iLast(m_xParagraphs->begin() + nLast);
2128 if ( iFirst < m_aVisibleBegin )
2129 iFirst = m_aVisibleBegin;
2130 if ( iLast > m_aVisibleEnd )
2131 iLast = m_aVisibleEnd;
2132 if ( iFirst < iLast )
2134 for ( Paragraphs::iterator i = iFirst; i != iLast; i++ )
2136 ::rtl::Reference< ParagraphImpl > xParagraph( getParagraph( i ) );
2137 if ( xParagraph.is() )
2139 xParagraph->notifyEvent(
2140 ::css::accessibility::AccessibleEventId::SELECTION_CHANGED,
2141 ::css::uno::Any(), ::css::uno::Any() );
2142 xParagraph->notifyEvent(
2143 ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED,
2144 ::css::uno::Any(), ::css::uno::Any() );
2150 void Document::justifySelection( TextPaM& rTextStart, TextPaM& rTextEnd )
2152 if ( rTextStart > rTextEnd )
2154 TextPaM aTextPaM( rTextStart );
2155 rTextStart = rTextEnd;
2156 rTextEnd = aTextPaM;
2160 void Document::disposeParagraphs()
2162 for (Paragraphs::iterator aIt(m_xParagraphs->begin());
2163 aIt != m_xParagraphs->end(); ++aIt)
2165 ::css::uno::Reference< ::css::lang::XComponent > xComponent(
2166 aIt->getParagraph().get(), ::css::uno::UNO_QUERY);
2167 if (xComponent.is())
2168 xComponent->dispose();
2172 // static
2173 ::css::uno::Any Document::mapFontColor(::Color const & rColor)
2175 return ::css::uno::makeAny(
2176 static_cast< ::sal_Int32 >(COLORDATA_RGB(rColor.GetColor())));
2177 // FIXME keep transparency?
2180 // static
2181 ::Color Document::mapFontColor(::css::uno::Any const & rColor)
2183 ::sal_Int32 nColor = 0;
2184 rColor >>= nColor;
2185 return ::Color(static_cast< ::ColorData >(nColor));
2188 // static
2189 ::css::uno::Any Document::mapFontWeight(::FontWeight nWeight)
2191 // Map from ::FontWeight to ::css:awt::FontWeight, depends on order of
2192 // elements in ::FontWeight (vcl/vclenum.hxx):
2193 static float const aWeight[]
2194 = { ::css::awt::FontWeight::DONTKNOW, // WEIGHT_DONTKNOW
2195 ::css::awt::FontWeight::THIN, // WEIGHT_THIN
2196 ::css::awt::FontWeight::ULTRALIGHT, // WEIGHT_ULTRALIGHT
2197 ::css::awt::FontWeight::LIGHT, // WEIGHT_LIGHT
2198 ::css::awt::FontWeight::SEMILIGHT, // WEIGHT_SEMILIGHT
2199 ::css::awt::FontWeight::NORMAL, // WEIGHT_NORMAL
2200 ::css::awt::FontWeight::NORMAL, // WEIGHT_MEDIUM
2201 ::css::awt::FontWeight::SEMIBOLD, // WEIGHT_SEMIBOLD
2202 ::css::awt::FontWeight::BOLD, // WEIGHT_BOLD
2203 ::css::awt::FontWeight::ULTRABOLD, // WEIGHT_ULTRABOLD
2204 ::css::awt::FontWeight::BLACK }; // WEIGHT_BLACK
2205 return ::css::uno::makeAny(aWeight[nWeight]);
2208 // static
2209 ::FontWeight Document::mapFontWeight(::css::uno::Any const & rWeight)
2211 float nWeight = ::css::awt::FontWeight::NORMAL;
2212 rWeight >>= nWeight;
2213 return nWeight <= ::css::awt::FontWeight::DONTKNOW ? WEIGHT_DONTKNOW
2214 : nWeight <= ::css::awt::FontWeight::THIN ? WEIGHT_THIN
2215 : nWeight <= ::css::awt::FontWeight::ULTRALIGHT ? WEIGHT_ULTRALIGHT
2216 : nWeight <= ::css::awt::FontWeight::LIGHT ? WEIGHT_LIGHT
2217 : nWeight <= ::css::awt::FontWeight::SEMILIGHT ? WEIGHT_SEMILIGHT
2218 : nWeight <= ::css::awt::FontWeight::NORMAL ? WEIGHT_NORMAL
2219 : nWeight <= ::css::awt::FontWeight::SEMIBOLD ? WEIGHT_SEMIBOLD
2220 : nWeight <= ::css::awt::FontWeight::BOLD ? WEIGHT_BOLD
2221 : nWeight <= ::css::awt::FontWeight::ULTRABOLD ? WEIGHT_ULTRABOLD
2222 : WEIGHT_BLACK;
2227 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */