| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_accessibility.hxx" |
| |
| #ifndef _TOOLKIT_AWT_VCLXACCESSIBLECOMPONENT_HXX_ |
| #include <accessibility/extended/textwindowaccessibility.hxx> |
| #endif |
| #include "comphelper/accessibleeventnotifier.hxx" |
| #include "unotools/accessiblerelationsethelper.hxx" |
| #include <unotools/accessiblestatesethelper.hxx> |
| #include <vcl/window.hxx> |
| #include <toolkit/helper/convert.hxx> |
| |
| #include <algorithm> |
| #include <vector> |
| #include <hash_map> |
| |
| namespace css = ::com::sun::star; |
| |
| namespace accessibility |
| { |
| ::sal_Int32 getSelectionType(::sal_Int32 nNewFirstPara, ::sal_Int32 nNewFirstPos, ::sal_Int32 nNewLastPara, ::sal_Int32 nNewLastPos); |
| void sendEvent(::sal_Int32 start, ::sal_Int32 end, ::sal_Int16 nEventId); |
| |
| // Both ::osl::Mutex and ParagraphBase implement acquire and release, and thus |
| // ::rtl::Reference< Paragraph > does not work. So ParagraphImpl was factored |
| // out and ::rtl::Reference< ParagraphImpl > is used instead. |
| class Paragraph: private ::osl::Mutex, public ParagraphImpl |
| { |
| public: |
| inline Paragraph(::rtl::Reference< Document > const & rDocument, |
| Paragraphs::size_type nNumber): |
| ParagraphImpl(rDocument, nNumber, *this) {} |
| }; |
| |
| void SfxListenerGuard::startListening(::SfxBroadcaster & rNotifier) |
| { |
| OSL_ENSURE(m_pNotifier == 0, "called more than once"); |
| m_pNotifier = &rNotifier; |
| m_rListener.StartListening(*m_pNotifier, true); |
| } |
| |
| void SfxListenerGuard::endListening() |
| { |
| if (m_pNotifier != 0) |
| { |
| m_rListener.EndListening(*m_pNotifier); |
| m_pNotifier = 0; |
| } |
| } |
| |
| void WindowListenerGuard::startListening(::Window & rNotifier) |
| { |
| OSL_ENSURE(m_pNotifier == 0, "called more than once"); |
| m_pNotifier = &rNotifier; |
| m_pNotifier->AddEventListener(m_aListener); |
| } |
| |
| void WindowListenerGuard::endListening() |
| { |
| if (m_pNotifier != 0) |
| { |
| m_pNotifier->RemoveEventListener(m_aListener); |
| m_pNotifier = 0; |
| } |
| } |
| |
| ParagraphImpl::ParagraphImpl(::rtl::Reference< Document > const & rDocument, |
| Paragraphs::size_type nNumber, |
| ::osl::Mutex & rMutex): |
| ParagraphBase(rMutex), |
| m_xDocument(rDocument), |
| m_nNumber(nNumber), |
| m_nClientId(0) |
| { |
| m_aParagraphText = m_xDocument->retrieveParagraphText(this); |
| } |
| |
| void |
| ParagraphImpl::numberChanged(bool bIncremented) |
| { |
| if (bIncremented) |
| ++m_nNumber; |
| else |
| --m_nNumber; |
| } |
| |
| void ParagraphImpl::textChanged() |
| { |
| ::rtl::OUString aParagraphText = implGetText(); |
| ::css::uno::Any aOldValue, aNewValue; |
| if ( implInitTextChangedEvent( m_aParagraphText, aParagraphText, aOldValue, aNewValue ) ) |
| { |
| m_aParagraphText = aParagraphText; |
| notifyEvent(::css::accessibility::AccessibleEventId:: |
| TEXT_CHANGED, |
| aOldValue, aNewValue); |
| } |
| } |
| |
| void ParagraphImpl::notifyEvent(::sal_Int16 nEventId, |
| ::css::uno::Any const & rOldValue, |
| ::css::uno::Any const & rNewValue) |
| { |
| if (m_nClientId) |
| comphelper::AccessibleEventNotifier::addEvent( m_nClientId, ::css::accessibility::AccessibleEventObject( |
| static_cast< ::cppu::OWeakObject * >(this), |
| nEventId, rNewValue, rOldValue) ); |
| } |
| |
| // virtual |
| ::css::uno::Reference< ::css::accessibility::XAccessibleContext > SAL_CALL |
| ParagraphImpl::getAccessibleContext() throw (::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| return this; |
| } |
| |
| // virtual |
| ::sal_Int32 SAL_CALL ParagraphImpl::getAccessibleChildCount() |
| throw (::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| return 0; |
| } |
| |
| // virtual |
| ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL |
| ParagraphImpl::getAccessibleChild(::sal_Int32) |
| throw (::css::lang::IndexOutOfBoundsException, |
| ::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| throw ::css::lang::IndexOutOfBoundsException( |
| ::rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM( |
| "textwindowaccessibility.cxx:" |
| " ParagraphImpl::getAccessibleChild")), |
| static_cast< ::css::uno::XWeak * >(this)); |
| } |
| |
| // virtual |
| ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL |
| ParagraphImpl::getAccessibleParent() |
| throw (::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| return m_xDocument->getAccessible(); |
| } |
| |
| // virtual |
| ::sal_Int32 SAL_CALL ParagraphImpl::getAccessibleIndexInParent() |
| throw (::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| return m_xDocument->retrieveParagraphIndex(this); |
| } |
| |
| // virtual |
| ::sal_Int16 SAL_CALL ParagraphImpl::getAccessibleRole() |
| throw (::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| return ::css::accessibility::AccessibleRole::PARAGRAPH; |
| } |
| |
| // virtual |
| ::rtl::OUString SAL_CALL ParagraphImpl::getAccessibleDescription() |
| throw (::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| return ::rtl::OUString(); |
| } |
| |
| // virtual |
| ::rtl::OUString SAL_CALL ParagraphImpl::getAccessibleName() |
| throw (::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| return ::rtl::OUString(); |
| } |
| |
| // virtual |
| ::css::uno::Reference< ::css::accessibility::XAccessibleRelationSet > |
| SAL_CALL ParagraphImpl::getAccessibleRelationSet() |
| throw (::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| return m_xDocument->retrieveParagraphRelationSet( this ); |
| } |
| |
| // virtual |
| ::css::uno::Reference< ::css::accessibility::XAccessibleStateSet > |
| SAL_CALL ParagraphImpl::getAccessibleStateSet() |
| throw (::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| |
| // FIXME Notification of changes (STATE_CHANGED) missing when |
| // m_rView.IsReadOnly() changes: |
| return new ::utl::AccessibleStateSetHelper( |
| m_xDocument->retrieveParagraphState(this)); |
| } |
| |
| // virtual |
| ::css::lang::Locale SAL_CALL ParagraphImpl::getLocale() |
| throw (::css::accessibility::IllegalAccessibleComponentStateException, |
| ::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| return m_xDocument->retrieveLocale(); |
| } |
| |
| // virtual |
| ::sal_Bool SAL_CALL ParagraphImpl::containsPoint(::css::awt::Point const & rPoint) |
| throw (::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| ::css::awt::Rectangle aRect(m_xDocument->retrieveParagraphBounds(this, |
| false)); |
| return rPoint.X >= 0 && rPoint.X < aRect.Width |
| && rPoint.Y >= 0 && rPoint.Y < aRect.Height; |
| } |
| |
| // virtual |
| ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL |
| ParagraphImpl::getAccessibleAtPoint(::css::awt::Point const &) |
| throw (::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| return 0; |
| } |
| |
| // virtual |
| ::css::awt::Rectangle SAL_CALL ParagraphImpl::getBounds() |
| throw (::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| return m_xDocument->retrieveParagraphBounds(this, false); |
| } |
| |
| // virtual |
| ::css::awt::Point SAL_CALL ParagraphImpl::getLocation() |
| throw (::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| ::css::awt::Rectangle aRect(m_xDocument->retrieveParagraphBounds(this, |
| false)); |
| return ::css::awt::Point(aRect.X, aRect.Y); |
| } |
| |
| // virtual |
| ::css::awt::Point SAL_CALL ParagraphImpl::getLocationOnScreen() |
| throw (::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| ::css::awt::Rectangle aRect(m_xDocument->retrieveParagraphBounds(this, |
| true)); |
| return ::css::awt::Point(aRect.X, aRect.Y); |
| } |
| |
| // virtual |
| ::css::awt::Size SAL_CALL ParagraphImpl::getSize() |
| throw (::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| ::css::awt::Rectangle aRect(m_xDocument->retrieveParagraphBounds(this, |
| false)); |
| return ::css::awt::Size(aRect.Width, aRect.Height); |
| } |
| |
| // virtual |
| void SAL_CALL ParagraphImpl::grabFocus() throw (::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| Window* pWindow = m_xDocument->GetWindow(); |
| if ( pWindow ) |
| { |
| pWindow->GrabFocus(); |
| } |
| try |
| { |
| m_xDocument->changeParagraphSelection(this, 0, 0); |
| } |
| catch (::css::lang::IndexOutOfBoundsException & rEx) |
| { |
| OSL_TRACE( |
| "textwindowaccessibility.cxx: ParagraphImpl::grabFocus:" |
| " caught unexpected %s\n", |
| ::rtl::OUStringToOString(rEx.Message, RTL_TEXTENCODING_UTF8). |
| getStr()); |
| } |
| } |
| |
| // virtual |
| ::css::uno::Any SAL_CALL ParagraphImpl::getAccessibleKeyBinding() |
| throw (::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| return ::css::uno::Any(); |
| } |
| |
| // virtual |
| ::css::util::Color SAL_CALL ParagraphImpl::getForeground() |
| throw (::css::uno::RuntimeException) |
| { |
| return 0; // TODO |
| } |
| |
| // virtual |
| ::css::util::Color SAL_CALL ParagraphImpl::getBackground() |
| throw (::css::uno::RuntimeException) |
| { |
| return 0; // TODO |
| } |
| |
| // virtual |
| ::sal_Int32 SAL_CALL ParagraphImpl::getCaretPosition() |
| throw (::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| return m_xDocument->retrieveParagraphCaretPosition(this); |
| } |
| |
| // virtual |
| ::sal_Bool SAL_CALL ParagraphImpl::setCaretPosition(::sal_Int32 nIndex) |
| throw (::css::lang::IndexOutOfBoundsException, |
| ::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| m_xDocument->changeParagraphSelection(this, nIndex, nIndex); |
| return true; |
| } |
| |
| // virtual |
| ::sal_Unicode SAL_CALL ParagraphImpl::getCharacter(::sal_Int32 nIndex) |
| throw (::css::lang::IndexOutOfBoundsException, |
| ::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| return OCommonAccessibleText::getCharacter(nIndex); |
| } |
| |
| // virtual |
| ::css::uno::Sequence< ::css::beans::PropertyValue > SAL_CALL |
| ParagraphImpl::getCharacterAttributes(::sal_Int32 nIndex, const ::com::sun::star::uno::Sequence< ::rtl::OUString >& aRequestedAttributes) |
| throw (::css::lang::IndexOutOfBoundsException, |
| ::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| return m_xDocument->retrieveCharacterAttributes( this, nIndex, aRequestedAttributes ); |
| } |
| |
| // virtual |
| ::css::awt::Rectangle SAL_CALL |
| ParagraphImpl::getCharacterBounds(::sal_Int32 nIndex) |
| throw (::css::lang::IndexOutOfBoundsException, |
| ::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| ::css::awt::Rectangle aBounds(m_xDocument->retrieveCharacterBounds(this, nIndex)); |
| ::css::awt::Rectangle aParaBounds(m_xDocument->retrieveParagraphBounds(this, false)); |
| aBounds.X -= aParaBounds.X; |
| aBounds.Y -= aParaBounds.Y; |
| return aBounds; |
| } |
| |
| // virtual |
| ::sal_Int32 SAL_CALL ParagraphImpl::getCharacterCount() |
| throw (::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| return OCommonAccessibleText::getCharacterCount(); |
| } |
| |
| // virtual |
| ::sal_Int32 SAL_CALL |
| ParagraphImpl::getIndexAtPoint(::css::awt::Point const & rPoint) |
| throw (::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| ::css::awt::Point aPoint(rPoint); |
| ::css::awt::Rectangle aParaBounds(m_xDocument->retrieveParagraphBounds(this, false)); |
| aPoint.X += aParaBounds.X; |
| aPoint.Y += aParaBounds.Y; |
| return m_xDocument->retrieveCharacterIndex(this, aPoint); |
| } |
| |
| // virtual |
| ::rtl::OUString SAL_CALL ParagraphImpl::getSelectedText() |
| throw (::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| |
| return OCommonAccessibleText::getSelectedText(); |
| } |
| |
| // virtual |
| ::sal_Int32 SAL_CALL ParagraphImpl::getSelectionStart() |
| throw (::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| return OCommonAccessibleText::getSelectionStart(); |
| } |
| |
| // virtual |
| ::sal_Int32 SAL_CALL ParagraphImpl::getSelectionEnd() |
| throw (::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| return OCommonAccessibleText::getSelectionEnd(); |
| } |
| |
| // virtual |
| ::sal_Bool SAL_CALL ParagraphImpl::setSelection(::sal_Int32 nStartIndex, |
| ::sal_Int32 nEndIndex) |
| throw (::css::lang::IndexOutOfBoundsException, |
| ::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| m_xDocument->changeParagraphSelection(this, nStartIndex, nEndIndex); |
| return true; |
| } |
| |
| // virtual |
| ::rtl::OUString SAL_CALL ParagraphImpl::getText() |
| throw (::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| return OCommonAccessibleText::getText(); |
| } |
| |
| // virtual |
| ::rtl::OUString SAL_CALL ParagraphImpl::getTextRange(::sal_Int32 nStartIndex, |
| ::sal_Int32 nEndIndex) |
| throw (::css::lang::IndexOutOfBoundsException, |
| ::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| return OCommonAccessibleText::getTextRange(nStartIndex, nEndIndex); |
| } |
| |
| // virtual |
| ::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) |
| { |
| checkDisposed(); |
| return OCommonAccessibleText::getTextAtIndex(nIndex, aTextType); |
| } |
| |
| // virtual |
| ::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) |
| { |
| checkDisposed(); |
| return OCommonAccessibleText::getTextBeforeIndex(nIndex, aTextType); |
| } |
| |
| // virtual |
| ::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) |
| { |
| checkDisposed(); |
| return OCommonAccessibleText::getTextBehindIndex(nIndex, aTextType); |
| } |
| |
| // virtual |
| ::sal_Bool SAL_CALL ParagraphImpl::copyText(::sal_Int32 nStartIndex, |
| ::sal_Int32 nEndIndex) |
| throw (::css::lang::IndexOutOfBoundsException, |
| ::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| m_xDocument->copyParagraphText(this, nStartIndex, nEndIndex); |
| return true; |
| } |
| |
| // virtual |
| ::sal_Bool SAL_CALL ParagraphImpl::cutText(::sal_Int32 nStartIndex, |
| ::sal_Int32 nEndIndex) |
| throw (::css::lang::IndexOutOfBoundsException, |
| ::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| m_xDocument->changeParagraphText(this, nStartIndex, nEndIndex, true, false, |
| ::rtl::OUString()); |
| return true; |
| } |
| |
| // virtual |
| ::sal_Bool SAL_CALL ParagraphImpl::pasteText(::sal_Int32 nIndex) |
| throw (::css::lang::IndexOutOfBoundsException, |
| ::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| m_xDocument->changeParagraphText(this, nIndex, nIndex, false, true, |
| ::rtl::OUString()); |
| return true; |
| } |
| |
| // virtual |
| ::sal_Bool SAL_CALL ParagraphImpl::deleteText(::sal_Int32 nStartIndex, |
| ::sal_Int32 nEndIndex) |
| throw (::css::lang::IndexOutOfBoundsException, |
| ::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| m_xDocument->changeParagraphText(this, nStartIndex, nEndIndex, false, false, |
| ::rtl::OUString()); |
| return true; |
| } |
| |
| // virtual |
| ::sal_Bool SAL_CALL ParagraphImpl::insertText(::rtl::OUString const & rText, |
| ::sal_Int32 nIndex) |
| throw (::css::lang::IndexOutOfBoundsException, |
| ::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| m_xDocument->changeParagraphText(this, nIndex, nIndex, false, false, rText); |
| return true; |
| } |
| |
| // virtual |
| ::sal_Bool SAL_CALL |
| ParagraphImpl::replaceText(::sal_Int32 nStartIndex, ::sal_Int32 nEndIndex, |
| ::rtl::OUString const & rReplacement) |
| throw (::css::lang::IndexOutOfBoundsException, |
| ::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| m_xDocument->changeParagraphText(this, nStartIndex, nEndIndex, false, false, |
| rReplacement); |
| return true; |
| } |
| |
| // virtual |
| ::sal_Bool SAL_CALL ParagraphImpl::setAttributes( |
| ::sal_Int32 nStartIndex, ::sal_Int32 nEndIndex, |
| ::css::uno::Sequence< ::css::beans::PropertyValue > const & rAttributeSet) |
| throw (::css::lang::IndexOutOfBoundsException, |
| ::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| m_xDocument->changeParagraphAttributes(this, nStartIndex, nEndIndex, |
| rAttributeSet); |
| return true; |
| } |
| |
| // virtual |
| ::sal_Bool SAL_CALL ParagraphImpl::setText(::rtl::OUString const & rText) |
| throw (::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| m_xDocument->changeParagraphText(this, rText); |
| return true; |
| } |
| |
| // virtual |
| ::css::uno::Sequence< ::css::beans::PropertyValue > SAL_CALL |
| ParagraphImpl::getDefaultAttributes(const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes) |
| throw (::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| return m_xDocument->retrieveDefaultAttributes( this, RequestedAttributes ); |
| } |
| |
| // virtual |
| ::css::uno::Sequence< ::css::beans::PropertyValue > SAL_CALL |
| ParagraphImpl::getRunAttributes(::sal_Int32 Index, const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes) |
| throw (::css::lang::IndexOutOfBoundsException, |
| ::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| return m_xDocument->retrieveRunAttributes( this, Index, RequestedAttributes ); |
| } |
| |
| // virtual |
| ::sal_Int32 SAL_CALL ParagraphImpl::getLineNumberAtIndex( ::sal_Int32 nIndex ) |
| throw (::css::lang::IndexOutOfBoundsException, |
| ::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| |
| ::sal_Int32 nLineNo = -1; |
| ::css::i18n::Boundary aBoundary = |
| m_xDocument->retrieveParagraphLineBoundary( this, nIndex, &nLineNo ); |
| |
| return nLineNo; |
| } |
| |
| // virtual |
| ::css::accessibility::TextSegment SAL_CALL ParagraphImpl::getTextAtLineNumber( ::sal_Int32 nLineNo ) |
| throw (::css::lang::IndexOutOfBoundsException, |
| ::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| |
| ::css::i18n::Boundary aBoundary = |
| m_xDocument->retrieveParagraphBoundaryOfLine( this, nLineNo ); |
| |
| return ::css::accessibility::TextSegment( getTextRange(aBoundary.startPos, aBoundary.endPos), |
| aBoundary.startPos, aBoundary.endPos); |
| } |
| |
| // virtual |
| ::css::accessibility::TextSegment SAL_CALL ParagraphImpl::getTextAtLineWithCaret( ) |
| throw (::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| |
| sal_Int32 nLineNo = getNumberOfLineWithCaret(); |
| |
| try { |
| return ( nLineNo >= 0 ) ? |
| getTextAtLineNumber( nLineNo ) : |
| ::css::accessibility::TextSegment(); |
| } catch (const ::css::lang::IndexOutOfBoundsException&) { |
| throw ::css::uno::RuntimeException( |
| ::rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM( |
| "textwindowaccessibility.cxx:" |
| " ParagraphImpl::getTextAtLineWithCaret") ), |
| static_cast< ::css::uno::XWeak * >( this ) ); |
| } |
| } |
| |
| // virtual |
| ::sal_Int32 SAL_CALL ParagraphImpl::getNumberOfLineWithCaret( ) |
| throw (::css::uno::RuntimeException) |
| { |
| checkDisposed(); |
| return m_xDocument->retrieveParagraphLineWithCursor(this); |
| } |
| |
| |
| // virtual |
| void SAL_CALL ParagraphImpl::addEventListener( |
| ::css::uno::Reference< |
| ::css::accessibility::XAccessibleEventListener > const & rListener) |
| throw (::css::uno::RuntimeException) |
| { |
| if (rListener.is()) |
| { |
| ::osl::ClearableMutexGuard aGuard(rBHelper.rMutex); |
| if (rBHelper.bDisposed || rBHelper.bInDispose) |
| { |
| aGuard.clear(); |
| rListener->disposing(::css::lang::EventObject( |
| static_cast< ::cppu::OWeakObject * >(this))); |
| } |
| else |
| { |
| if (!m_nClientId) |
| m_nClientId = comphelper::AccessibleEventNotifier::registerClient( ); |
| comphelper::AccessibleEventNotifier::addEventListener( m_nClientId, rListener ); |
| } |
| } |
| } |
| |
| // virtual |
| void SAL_CALL ParagraphImpl::removeEventListener( |
| ::css::uno::Reference< |
| ::css::accessibility::XAccessibleEventListener > const & rListener) |
| throw (::css::uno::RuntimeException) |
| { |
| comphelper::AccessibleEventNotifier::TClientId nId = 0; |
| { |
| ::osl::ClearableMutexGuard aGuard(rBHelper.rMutex); |
| if (rListener.is() && m_nClientId != 0 |
| && comphelper::AccessibleEventNotifier::removeEventListener( m_nClientId, rListener ) == 0) |
| { |
| nId = m_nClientId; |
| m_nClientId = 0; |
| } |
| } |
| if (nId != 0) |
| { |
| // no listeners anymore |
| // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client), |
| // and at least to us not firing any events anymore, in case somebody calls |
| // NotifyAccessibleEvent, again |
| comphelper::AccessibleEventNotifier::revokeClient(nId); |
| } |
| } |
| |
| // virtual |
| void SAL_CALL ParagraphImpl::disposing() |
| { |
| comphelper::AccessibleEventNotifier::TClientId nId = 0; |
| { |
| ::osl::ClearableMutexGuard aGuard(rBHelper.rMutex); |
| nId = m_nClientId; |
| m_nClientId = 0; |
| } |
| if (nId != 0) |
| comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing(nId, *this); |
| } |
| |
| // virtual |
| ::rtl::OUString ParagraphImpl::implGetText() |
| { |
| return m_xDocument->retrieveParagraphText(this); |
| } |
| |
| // virtual |
| ::css::lang::Locale ParagraphImpl::implGetLocale() |
| { |
| return m_xDocument->retrieveLocale(); |
| } |
| |
| // virtual |
| void ParagraphImpl::implGetSelection(::sal_Int32 & rStartIndex, |
| ::sal_Int32 & rEndIndex) |
| { |
| m_xDocument->retrieveParagraphSelection(this, &rStartIndex, &rEndIndex); |
| } |
| |
| // virtual |
| void ParagraphImpl::implGetParagraphBoundary( ::css::i18n::Boundary& rBoundary, |
| ::sal_Int32 nIndex ) |
| { |
| ::rtl::OUString sText( implGetText() ); |
| ::sal_Int32 nLength = sText.getLength(); |
| |
| if ( implIsValidIndex( nIndex, nLength ) ) |
| { |
| rBoundary.startPos = 0; |
| rBoundary.endPos = nLength; |
| } |
| else |
| { |
| rBoundary.startPos = nIndex; |
| rBoundary.endPos = nIndex; |
| } |
| } |
| |
| // virtual |
| void ParagraphImpl::implGetLineBoundary( ::css::i18n::Boundary& rBoundary, |
| ::sal_Int32 nIndex ) |
| { |
| ::rtl::OUString sText( implGetText() ); |
| ::sal_Int32 nLength = sText.getLength(); |
| |
| if ( implIsValidIndex( nIndex, nLength ) || nIndex == nLength ) |
| { |
| ::css::i18n::Boundary aBoundary = |
| m_xDocument->retrieveParagraphLineBoundary( this, nIndex ); |
| rBoundary.startPos = aBoundary.startPos; |
| rBoundary.endPos = aBoundary.endPos; |
| } |
| else |
| { |
| rBoundary.startPos = nIndex; |
| rBoundary.endPos = nIndex; |
| } |
| } |
| |
| |
| void ParagraphImpl::checkDisposed() |
| { |
| ::osl::MutexGuard aGuard(rBHelper.rMutex); |
| if (!(rBHelper.bDisposed || rBHelper.bInDispose)) |
| return; |
| throw ::css::lang::DisposedException( |
| ::rtl::OUString(), static_cast< ::css::uno::XWeak * >(this)); |
| } |
| |
| Document::Document(::VCLXWindow * pVclXWindow, ::TextEngine & rEngine, |
| ::TextView & rView, bool bCompoundControlChild): |
| VCLXAccessibleComponent(pVclXWindow), |
| m_xAccessible(pVclXWindow), |
| m_rEngine(rEngine), |
| m_rView(rView), |
| m_aEngineListener(*this), |
| m_aViewListener(LINK(this, Document, WindowEventHandler)), |
| m_bCompoundControlChild(bCompoundControlChild) |
| {} |
| |
| ::css::lang::Locale Document::retrieveLocale() |
| { |
| ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock()); |
| return m_rEngine.GetLocale(); |
| } |
| |
| ::sal_Int32 Document::retrieveParagraphIndex(ParagraphImpl const * pParagraph) |
| { |
| ::osl::MutexGuard aInternalGuard(GetMutex()); |
| |
| // If a client holds on to a Paragraph that is no longer visible, it can |
| // happen that this Paragraph lies outside the range from m_aVisibleBegin |
| // to m_aVisibleEnd. In that case, return -1 instead of a valid index: |
| Paragraphs::iterator aPara(m_xParagraphs->begin() |
| + pParagraph->getNumber()); |
| return aPara < m_aVisibleBegin || aPara >= m_aVisibleEnd |
| ? -1 : static_cast< ::sal_Int32 >(aPara - m_aVisibleBegin); |
| // XXX numeric overflow |
| } |
| |
| ::sal_Int64 Document::retrieveParagraphState(ParagraphImpl const * pParagraph) |
| { |
| ::osl::MutexGuard aInternalGuard(GetMutex()); |
| |
| // If a client holds on to a Paragraph that is no longer visible, it can |
| // happen that this Paragraph lies outside the range from m_aVisibleBegin |
| // to m_aVisibleEnd. In that case, it is neither VISIBLE nor SHOWING: |
| ::sal_Int64 nState |
| = (static_cast< ::sal_Int64 >(1) |
| << ::css::accessibility::AccessibleStateType::ENABLED) |
| | (static_cast< ::sal_Int64 >(1) |
| << ::css::accessibility::AccessibleStateType::SENSITIVE) |
| | (static_cast< ::sal_Int64 >(1) |
| << ::css::accessibility::AccessibleStateType::FOCUSABLE) |
| | (static_cast< ::sal_Int64 >(1) |
| << ::css::accessibility::AccessibleStateType::MULTI_LINE); |
| if (!m_rView.IsReadOnly()) |
| nState |= (static_cast< ::sal_Int64 >(1) |
| << ::css::accessibility::AccessibleStateType::EDITABLE); |
| Paragraphs::iterator aPara(m_xParagraphs->begin() |
| + pParagraph->getNumber()); |
| if (aPara >= m_aVisibleBegin && aPara < m_aVisibleEnd) |
| { |
| nState |
| |= (static_cast< ::sal_Int64 >(1) |
| << ::css::accessibility::AccessibleStateType::VISIBLE) |
| | (static_cast< ::sal_Int64 >(1) |
| << ::css::accessibility::AccessibleStateType::SHOWING); |
| if (aPara == m_aFocused) |
| nState |= (static_cast< ::sal_Int64 >(1) |
| << ::css::accessibility::AccessibleStateType::FOCUSED); |
| } |
| return nState; |
| }; |
| |
| ::css::awt::Rectangle |
| Document::retrieveParagraphBounds(ParagraphImpl const * pParagraph, |
| bool bAbsolute) |
| { |
| ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock()); |
| ::osl::MutexGuard aInternalGuard(GetMutex()); |
| |
| // If a client holds on to a Paragraph that is no longer visible (as it |
| // scrolled out the top of the view), it can happen that this Paragraph |
| // lies before m_aVisibleBegin. In that case, calculate the vertical |
| // position of the Paragraph starting at paragraph 0, otherwise optimize |
| // and start at m_aVisibleBegin: |
| Paragraphs::iterator aPara(m_xParagraphs->begin() |
| + pParagraph->getNumber()); |
| ::sal_Int32 nPos; |
| Paragraphs::iterator aIt; |
| if (aPara < m_aVisibleBegin) |
| { |
| nPos = 0; |
| aIt = m_xParagraphs->begin(); |
| } |
| else |
| { |
| nPos = m_nViewOffset - m_nVisibleBeginOffset; |
| aIt = m_aVisibleBegin; |
| } |
| for (; aIt != aPara; ++aIt) |
| nPos += aIt->getHeight(); |
| |
| Point aOrig(0, 0); |
| if (bAbsolute) |
| aOrig = m_rView.GetWindow()->OutputToAbsoluteScreenPixel(aOrig); |
| |
| return ::css::awt::Rectangle( |
| static_cast< ::sal_Int32 >(aOrig.X()), |
| static_cast< ::sal_Int32 >(aOrig.Y()) + nPos - m_nViewOffset, |
| m_rView.GetWindow()->GetOutputSizePixel().Width(), aPara->getHeight()); |
| // XXX numeric overflow (3x) |
| } |
| |
| ::rtl::OUString |
| Document::retrieveParagraphText(ParagraphImpl const * pParagraph) |
| { |
| ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock()); |
| ::osl::MutexGuard aInternalGuard(GetMutex()); |
| return m_rEngine.GetText(static_cast< ::sal_uLong >(pParagraph->getNumber())); |
| // numeric overflow cannot happen here |
| } |
| |
| void Document::retrieveParagraphSelection(ParagraphImpl const * pParagraph, |
| ::sal_Int32 * pBegin, |
| ::sal_Int32 * pEnd) |
| { |
| ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock()); |
| ::osl::MutexGuard aInternalGuard(GetMutex()); |
| ::TextSelection const & rSelection = m_rView.GetSelection(); |
| Paragraphs::size_type nNumber = pParagraph->getNumber(); |
| TextPaM aStartPaM( rSelection.GetStart() ); |
| TextPaM aEndPaM( rSelection.GetEnd() ); |
| TextPaM aMinPaM( ::std::min( aStartPaM, aEndPaM ) ); |
| TextPaM aMaxPaM( ::std::max( aStartPaM, aEndPaM ) ); |
| |
| if ( nNumber >= aMinPaM.GetPara() && nNumber <= aMaxPaM.GetPara() ) |
| { |
| *pBegin = nNumber > aMinPaM.GetPara() |
| ? 0 |
| : static_cast< ::sal_Int32 >( aMinPaM.GetIndex() ); |
| // XXX numeric overflow |
| *pEnd = nNumber < aMaxPaM.GetPara() |
| ? static_cast< ::sal_Int32 >( m_rEngine.GetText(static_cast< ::sal_uLong >(nNumber)).Len() ) |
| : static_cast< ::sal_Int32 >( aMaxPaM.GetIndex() ); |
| // XXX numeric overflow (3x) |
| |
| if ( aStartPaM > aEndPaM ) |
| ::std::swap( *pBegin, *pEnd ); |
| } |
| else |
| { |
| *pBegin = 0; |
| *pEnd = 0; |
| } |
| } |
| |
| ::sal_Int32 Document::retrieveParagraphCaretPosition(ParagraphImpl const * pParagraph) |
| { |
| ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock()); |
| ::osl::MutexGuard aInternalGuard(GetMutex()); |
| ::TextSelection const & rSelection = m_rView.GetSelection(); |
| Paragraphs::size_type nNumber = pParagraph->getNumber(); |
| TextPaM aEndPaM( rSelection.GetEnd() ); |
| |
| return aEndPaM.GetPara() == nNumber |
| ? static_cast< ::sal_Int32 >(aEndPaM.GetIndex()) : -1; |
| } |
| |
| ::css::awt::Rectangle |
| Document::retrieveCharacterBounds(ParagraphImpl const * pParagraph, |
| ::sal_Int32 nIndex) |
| { |
| ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock()); |
| ::osl::MutexGuard aInternalGuard(GetMutex()); |
| ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber()); |
| sal_Int32 nLength = m_rEngine.GetText(nNumber).Len(); |
| // XXX numeric overflow |
| if (nIndex < 0 || nIndex > nLength) |
| throw ::css::lang::IndexOutOfBoundsException( |
| ::rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM( |
| "textwindowaccessibility.cxx:" |
| " Document::retrieveCharacterAttributes")), |
| static_cast< ::css::uno::XWeak * >(this)); |
| ::css::awt::Rectangle aBounds( 0, 0, 0, 0 ); |
| if ( nIndex == nLength ) |
| { |
| aBounds = AWTRectangle( |
| m_rEngine.PaMtoEditCursor(::TextPaM(nNumber, |
| static_cast< ::sal_uInt16 >(nIndex)))); |
| } |
| else |
| { |
| ::Rectangle aLeft( |
| m_rEngine.PaMtoEditCursor(::TextPaM(nNumber, |
| static_cast< ::sal_uInt16 >(nIndex)))); |
| // XXX numeric overflow |
| ::Rectangle aRight( |
| m_rEngine.PaMtoEditCursor(::TextPaM(nNumber, |
| static_cast< ::sal_uInt16 >(nIndex) |
| + 1))); |
| // XXX numeric overflow (2x) |
| // FIXME If the vertical extends of the two cursors do not match, assume |
| // nIndex is the last character on the line; the bounding box will then |
| // extend to m_rEnginge.GetMaxTextWidth(): |
| ::sal_Int32 nWidth = (aLeft.Top() == aRight.Top() |
| && aLeft.Bottom() == aRight.Bottom()) |
| ? static_cast< ::sal_Int32 >(aRight.Left() - aLeft.Left()) |
| : static_cast< ::sal_Int32 >(m_rEngine.GetMaxTextWidth() |
| - aLeft.Left()); |
| // XXX numeric overflow (4x) |
| aBounds = ::css::awt::Rectangle(static_cast< ::sal_Int32 >(aLeft.Left()), |
| static_cast< ::sal_Int32 >(aLeft.Top() - m_nViewOffset), |
| nWidth, |
| static_cast< ::sal_Int32 >(aLeft.Bottom() |
| - aLeft.Top())); |
| // XXX numeric overflow (4x) |
| } |
| return aBounds; |
| } |
| |
| ::sal_Int32 Document::retrieveCharacterIndex(ParagraphImpl const * pParagraph, |
| ::css::awt::Point const & rPoint) |
| { |
| ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock()); |
| ::osl::MutexGuard aInternalGuard(GetMutex()); |
| ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber()); |
| // XXX numeric overflow |
| ::TextPaM aPaM(m_rEngine.GetPaM(::Point(static_cast< long >(rPoint.X), |
| static_cast< long >(rPoint.Y)))); |
| // XXX numeric overflow (2x) |
| return aPaM.GetPara() == nNumber |
| ? static_cast< ::sal_Int32 >(aPaM.GetIndex()) : -1; |
| // XXX numeric overflow |
| } |
| |
| struct IndexCompare |
| { |
| const ::css::beans::PropertyValue* pValues; |
| IndexCompare( const ::css::beans::PropertyValue* pVals ) : pValues(pVals) {} |
| bool operator() ( const sal_Int32& a, const sal_Int32& b ) const |
| { |
| return (pValues[a].Name < pValues[b].Name) ? true : false; |
| } |
| }; |
| |
| ::css::uno::Sequence< ::css::beans::PropertyValue > |
| Document::retrieveCharacterAttributes( |
| ParagraphImpl const * pParagraph, ::sal_Int32 nIndex, |
| const ::css::uno::Sequence< ::rtl::OUString >& aRequestedAttributes) |
| { |
| ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock()); |
| |
| Font aFont = m_rEngine.GetFont(); |
| const sal_Int32 AttributeCount = 9; |
| sal_Int32 i = 0; |
| ::css::uno::Sequence< ::css::beans::PropertyValue > aAttribs( AttributeCount ); |
| //character background color |
| { |
| aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharBackColor")); |
| aAttribs[i].Handle = -1; |
| aAttribs[i].Value = mapFontColor( aFont.GetFillColor() ); |
| aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE; |
| i++; |
| } |
| //character color |
| { |
| aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharColor")); |
| aAttribs[i].Handle = -1; |
| //aAttribs[i].Value = mapFontColor( aFont.GetColor() ); |
| aAttribs[i].Value = mapFontColor( m_rEngine.GetTextColor() ); |
| aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE; |
| i++; |
| } |
| //character font name |
| { |
| aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharFontName")); |
| aAttribs[i].Handle = -1; |
| aAttribs[i].Value = ::css::uno::makeAny( (::rtl::OUString)aFont.GetName() ); |
| aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE; |
| i++; |
| } |
| //character height |
| { |
| aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharHeight")); |
| aAttribs[i].Handle = -1; |
| aAttribs[i].Value = ::css::uno::makeAny( (sal_Int16)aFont.GetHeight() ); |
| aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE; |
| i++; |
| } |
| //character posture |
| { |
| aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharPosture")); |
| aAttribs[i].Handle = -1; |
| aAttribs[i].Value = ::css::uno::makeAny( (sal_Int16)aFont.GetItalic() ); |
| aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE; |
| i++; |
| } |
| //character relief |
| /*{ |
| aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharRelief")); |
| aAttribs[i].Handle = -1; |
| aAttribs[i].Value = ::css::uno::makeAny( (sal_Int16)aFont.GetRelief() ); |
| aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE; |
| i++; |
| }*/ |
| //character strikeout |
| { |
| aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharStrikeout")); |
| aAttribs[i].Handle = -1; |
| aAttribs[i].Value = ::css::uno::makeAny( (sal_Int16)aFont.GetStrikeout() ); |
| aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE; |
| i++; |
| } |
| //character underline |
| { |
| aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharUnderline")); |
| aAttribs[i].Handle = -1; |
| aAttribs[i].Value = ::css::uno::makeAny( (sal_Int16)aFont.GetUnderline() ); |
| aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE; |
| i++; |
| } |
| //character weight |
| { |
| aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharWeight")); |
| aAttribs[i].Handle = -1; |
| aAttribs[i].Value = ::css::uno::makeAny( (float)aFont.GetWeight() ); |
| aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE; |
| i++; |
| } |
| //character alignment |
| { |
| aAttribs[i].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ParaAdjust")); |
| aAttribs[i].Handle = -1; |
| aAttribs[i].Value = ::css::uno::makeAny( (sal_Int16)m_rEngine.GetTextAlign() ); |
| aAttribs[i].State = ::css::beans::PropertyState_DIRECT_VALUE; |
| i++; |
| } |
| ::osl::MutexGuard aInternalGuard(GetMutex()); |
| ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber()); |
| // XXX numeric overflow |
| // nIndex can be equal to Len(); |
| //if (nIndex < 0 || nIndex >= m_rEngine.GetText(nNumber).Len()) |
| if (nIndex < 0 || nIndex > m_rEngine.GetText(nNumber).Len()) |
| throw ::css::lang::IndexOutOfBoundsException( |
| ::rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM( |
| "textwindowaccessibility.cxx:" |
| " Document::retrieveCharacterAttributes")), |
| static_cast< ::css::uno::XWeak * >(this)); |
| |
| // retrieve default attributes |
| tPropValMap aCharAttrSeq; |
| retrieveDefaultAttributesImpl( pParagraph, aRequestedAttributes, aCharAttrSeq ); |
| |
| // retrieve run attributes |
| tPropValMap aRunAttrSeq; |
| retrieveRunAttributesImpl( pParagraph, nIndex, aRequestedAttributes, aRunAttrSeq ); |
| |
| // merge default and run attributes |
| for ( tPropValMap::const_iterator aRunIter = aRunAttrSeq.begin(); |
| aRunIter != aRunAttrSeq.end(); |
| ++aRunIter ) |
| { |
| aCharAttrSeq[ aRunIter->first ] = aRunIter->second; |
| } |
| |
| ::css::beans::PropertyValue* pValues = aAttribs.getArray(); |
| for (i = 0; i < AttributeCount; i++,pValues++) |
| { |
| aCharAttrSeq[ pValues->Name ] = *pValues; |
| } |
| |
| ::css::uno::Sequence< ::css::beans::PropertyValue > aRes = convertHashMapToSequence( aCharAttrSeq ); |
| |
| // sort the attributes |
| sal_Int32 nLength = aRes.getLength(); |
| const ::css::beans::PropertyValue* pPairs = aRes.getConstArray(); |
| sal_Int32* pIndices = new sal_Int32[nLength]; |
| for( i = 0; i < nLength; i++ ) |
| pIndices[i] = i; |
| std::sort( &pIndices[0], &pIndices[nLength], IndexCompare(pPairs) ); |
| // create sorted sequences accoring to index array |
| ::css::uno::Sequence< ::css::beans::PropertyValue > aNewValues( nLength ); |
| ::css::beans::PropertyValue* pNewValues = aNewValues.getArray(); |
| for( i = 0; i < nLength; i++ ) |
| { |
| pNewValues[i] = pPairs[pIndices[i]]; |
| } |
| delete[] pIndices; |
| |
| return aNewValues; |
| } |
| |
| void Document::retrieveDefaultAttributesImpl( |
| ParagraphImpl const * pParagraph, |
| const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes, |
| tPropValMap& rDefAttrSeq) |
| { |
| // default attributes are not supported by text engine |
| (void) pParagraph; |
| (void) RequestedAttributes; |
| (void) rDefAttrSeq; |
| } |
| |
| ::css::uno::Sequence< ::css::beans::PropertyValue > |
| Document::retrieveDefaultAttributes( |
| ParagraphImpl const * pParagraph, |
| const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes) |
| { |
| ::osl::Guard< ::comphelper::IMutex > aExternalGuard( getExternalLock() ); |
| ::osl::MutexGuard aInternalGuard( GetMutex() ); |
| |
| tPropValMap aDefAttrSeq; |
| retrieveDefaultAttributesImpl( pParagraph, RequestedAttributes, aDefAttrSeq ); |
| return convertHashMapToSequence( aDefAttrSeq ); |
| } |
| |
| // static |
| ::css::uno::Sequence< ::css::beans::PropertyValue > |
| Document::convertHashMapToSequence(tPropValMap& rAttrSeq) |
| { |
| ::css::uno::Sequence< ::css::beans::PropertyValue > aValues( rAttrSeq.size() ); |
| ::css::beans::PropertyValue* pValues = aValues.getArray(); |
| ::sal_Int32 i = 0; |
| for ( tPropValMap::const_iterator aIter = rAttrSeq.begin(); |
| aIter != rAttrSeq.end(); |
| ++aIter ) |
| { |
| pValues[i] = aIter->second; |
| ++i; |
| } |
| return aValues; |
| } |
| |
| void Document::retrieveRunAttributesImpl( |
| ParagraphImpl const * pParagraph, ::sal_Int32 Index, |
| const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes, |
| tPropValMap& rRunAttrSeq) |
| { |
| ::sal_uLong nNumber = static_cast< ::sal_uLong >( pParagraph->getNumber() ); |
| ::TextPaM aPaM( nNumber, static_cast< ::sal_uInt16 >( Index ) ); |
| // XXX numeric overflow |
| // FIXME TEXTATTR_HYPERLINK ignored: |
| ::TextAttribFontColor const * pColor |
| = static_cast< ::TextAttribFontColor const * >( |
| m_rEngine.FindAttrib( aPaM, TEXTATTR_FONTCOLOR ) ); |
| ::TextAttribFontWeight const * pWeight |
| = static_cast< ::TextAttribFontWeight const * >( |
| m_rEngine.FindAttrib( aPaM, TEXTATTR_FONTWEIGHT ) ); |
| tPropValMap aRunAttrSeq; |
| if ( pColor ) |
| { |
| ::css::beans::PropertyValue aPropVal; |
| aPropVal.Name = |
| ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CharColor" ) ); |
| aPropVal.Handle = -1; |
| aPropVal.Value = mapFontColor( pColor->GetColor() ); |
| aPropVal.State = ::css::beans::PropertyState_DIRECT_VALUE; |
| aRunAttrSeq[ aPropVal.Name ] = aPropVal; |
| } |
| if ( pWeight ) |
| { |
| ::css::beans::PropertyValue aPropVal; |
| aPropVal.Name = |
| ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CharWeight" ) ); |
| aPropVal.Handle = -1; |
| aPropVal.Value = mapFontWeight( pWeight->getFontWeight() ); |
| aPropVal.State = ::css::beans::PropertyState_DIRECT_VALUE; |
| aRunAttrSeq[ aPropVal.Name ] = aPropVal; |
| } |
| if ( RequestedAttributes.getLength() == 0 ) |
| { |
| rRunAttrSeq = aRunAttrSeq; |
| } |
| else |
| { |
| const ::rtl::OUString* pReqAttrs = RequestedAttributes.getConstArray(); |
| const ::sal_Int32 nLength = RequestedAttributes.getLength(); |
| for ( ::sal_Int32 i = 0; i < nLength; ++i ) |
| { |
| tPropValMap::iterator aIter = aRunAttrSeq.find( pReqAttrs[i] ); |
| if ( aIter != aRunAttrSeq.end() ) |
| { |
| rRunAttrSeq[ (*aIter).first ] = (*aIter).second; |
| } |
| } |
| } |
| } |
| |
| ::css::uno::Sequence< ::css::beans::PropertyValue > |
| Document::retrieveRunAttributes( |
| ParagraphImpl const * pParagraph, ::sal_Int32 Index, |
| const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes) |
| { |
| ::osl::Guard< ::comphelper::IMutex > aExternalGuard( getExternalLock() ); |
| ::osl::MutexGuard aInternalGuard( GetMutex() ); |
| ::sal_uLong nNumber = static_cast< ::sal_uLong >( pParagraph->getNumber() ); |
| // XXX numeric overflow |
| if ( Index < 0 || Index >= m_rEngine.GetText(nNumber).Len() ) |
| throw ::css::lang::IndexOutOfBoundsException( |
| ::rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM( |
| "textwindowaccessibility.cxx:" |
| " Document::retrieveRunAttributes") ), |
| static_cast< ::css::uno::XWeak * >( this ) ); |
| |
| tPropValMap aRunAttrSeq; |
| retrieveRunAttributesImpl( pParagraph, Index, RequestedAttributes, aRunAttrSeq ); |
| return convertHashMapToSequence( aRunAttrSeq ); |
| } |
| |
| void Document::changeParagraphText(ParagraphImpl * pParagraph, |
| ::rtl::OUString const & rText) |
| { |
| ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock()); |
| { |
| ::osl::MutexGuard aInternalGuard(GetMutex()); |
| ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber()); |
| // XXX numeric overflow |
| changeParagraphText(nNumber, 0, m_rEngine.GetTextLen(nNumber), false, |
| false, rText); |
| } |
| } |
| |
| void Document::changeParagraphText(ParagraphImpl * pParagraph, |
| ::sal_Int32 nBegin, ::sal_Int32 nEnd, |
| bool bCut, bool bPaste, |
| ::rtl::OUString const & rText) |
| { |
| ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock()); |
| { |
| ::osl::MutexGuard aInternalGuard(GetMutex()); |
| ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber()); |
| // XXX numeric overflow |
| if (nBegin < 0 || nBegin > nEnd |
| || nEnd > m_rEngine.GetText(nNumber).Len()) |
| throw ::css::lang::IndexOutOfBoundsException( |
| ::rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM( |
| "textwindowaccessibility.cxx:" |
| " Document::changeParagraphText")), |
| static_cast< ::css::uno::XWeak * >(this)); |
| changeParagraphText(nNumber, static_cast< ::sal_uInt16 >(nBegin), |
| static_cast< ::sal_uInt16 >(nEnd), bCut, bPaste, rText); |
| // XXX numeric overflow (2x) |
| } |
| } |
| |
| void Document::copyParagraphText(ParagraphImpl const * pParagraph, |
| ::sal_Int32 nBegin, ::sal_Int32 nEnd) |
| { |
| ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock()); |
| { |
| ::osl::MutexGuard aInternalGuard(GetMutex()); |
| ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber()); |
| // XXX numeric overflow |
| if (nBegin < 0 || nBegin > nEnd |
| || nEnd > m_rEngine.GetText(nNumber).Len()) |
| throw ::css::lang::IndexOutOfBoundsException( |
| ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( |
| "textwindowaccessibility.cxx:" |
| " Document::copyParagraphText")), |
| static_cast< ::css::uno::XWeak * >(this)); |
| m_rView.SetSelection( |
| ::TextSelection(::TextPaM(nNumber, static_cast< ::sal_uInt16 >(nBegin)), |
| ::TextPaM(nNumber, static_cast< ::sal_uInt16 >(nEnd)))); |
| // XXX numeric overflow (2x) |
| m_rView.Copy(); |
| } |
| } |
| |
| void Document::changeParagraphAttributes( |
| ParagraphImpl * pParagraph, ::sal_Int32 nBegin, ::sal_Int32 nEnd, |
| ::css::uno::Sequence< ::css::beans::PropertyValue > const & rAttributeSet) |
| { |
| ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock()); |
| { |
| ::osl::MutexGuard aInternalGuard(GetMutex()); |
| ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber()); |
| // XXX numeric overflow |
| if (nBegin < 0 || nBegin > nEnd |
| || nEnd > m_rEngine.GetText(nNumber).Len()) |
| throw ::css::lang::IndexOutOfBoundsException( |
| ::rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM( |
| "textwindowaccessibility.cxx:" |
| " Document::changeParagraphAttributes")), |
| static_cast< ::css::uno::XWeak * >(this)); |
| |
| // FIXME The new attributes are added to any attributes already set, |
| // they do not replace the old attributes as required by |
| // XAccessibleEditableText.setAttributes: |
| for (::sal_Int32 i = 0; i < rAttributeSet.getLength(); ++i) |
| if (rAttributeSet[i].Name.equalsAsciiL( |
| RTL_CONSTASCII_STRINGPARAM("CharColor"))) |
| m_rEngine.SetAttrib(::TextAttribFontColor( |
| mapFontColor(rAttributeSet[i].Value)), |
| nNumber, static_cast< ::sal_uInt16 >(nBegin), |
| static_cast< ::sal_uInt16 >(nEnd)); |
| // XXX numeric overflow (2x) |
| else if (rAttributeSet[i].Name.equalsAsciiL( |
| RTL_CONSTASCII_STRINGPARAM("CharWeight"))) |
| m_rEngine.SetAttrib(::TextAttribFontWeight( |
| mapFontWeight(rAttributeSet[i].Value)), |
| nNumber, static_cast< ::sal_uInt16 >(nBegin), |
| static_cast< ::sal_uInt16 >(nEnd)); |
| // XXX numeric overflow (2x) |
| } |
| } |
| |
| void Document::changeParagraphSelection(ParagraphImpl * pParagraph, |
| ::sal_Int32 nBegin, ::sal_Int32 nEnd) |
| { |
| ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock()); |
| { |
| ::osl::MutexGuard aInternalGuard(GetMutex()); |
| ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber()); |
| // XXX numeric overflow |
| if (nBegin < 0 || nBegin > nEnd |
| || nEnd > m_rEngine.GetText(nNumber).Len()) |
| throw ::css::lang::IndexOutOfBoundsException( |
| ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( |
| "textwindowaccessibility.cxx:" |
| " Document::changeParagraphSelection")), |
| static_cast< ::css::uno::XWeak * >(this)); |
| m_rView.SetSelection( |
| ::TextSelection(::TextPaM(nNumber, static_cast< ::sal_uInt16 >(nBegin)), |
| ::TextPaM(nNumber, static_cast< ::sal_uInt16 >(nEnd)))); |
| // XXX numeric overflow (2x) |
| } |
| } |
| |
| ::css::i18n::Boundary |
| Document::retrieveParagraphLineBoundary( ParagraphImpl const * pParagraph, |
| ::sal_Int32 nIndex, ::sal_Int32 *pLineNo ) |
| { |
| ::css::i18n::Boundary aBoundary; |
| aBoundary.startPos = nIndex; |
| aBoundary.endPos = nIndex; |
| |
| ::osl::Guard< ::comphelper::IMutex > aExternalGuard( getExternalLock() ); |
| { |
| ::osl::MutexGuard aInternalGuard( GetMutex() ); |
| ::sal_uLong nNumber = static_cast< ::sal_uLong >( pParagraph->getNumber() ); |
| if ( nIndex < 0 || nIndex > m_rEngine.GetText( nNumber ).Len() ) |
| throw ::css::lang::IndexOutOfBoundsException( |
| ::rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM( |
| "textwindowaccessibility.cxx:" |
| " Document::retrieveParagraphLineBoundary" ) ), |
| static_cast< ::css::uno::XWeak * >( this ) ); |
| ::sal_Int32 nLineStart = 0; |
| ::sal_Int32 nLineEnd = 0; |
| ::sal_uInt16 nLineCount = m_rEngine.GetLineCount( nNumber ); |
| for ( ::sal_uInt16 nLine = 0; nLine < nLineCount; ++nLine ) |
| { |
| ::sal_Int32 nLineLength = static_cast< ::sal_Int32 >( |
| m_rEngine.GetLineLen( nNumber, nLine ) ); |
| nLineStart = nLineEnd; |
| nLineEnd += nLineLength; |
| if ( nIndex >= nLineStart && ( ( nLine == nLineCount - 1 ) ? nIndex <= nLineEnd : nIndex < nLineEnd ) ) |
| { |
| aBoundary.startPos = nLineStart; |
| aBoundary.endPos = nLineEnd; |
| if( pLineNo ) |
| pLineNo[0] = nLine; |
| break; |
| } |
| } |
| } |
| |
| return aBoundary; |
| } |
| |
| ::css::i18n::Boundary |
| Document::retrieveParagraphBoundaryOfLine( ParagraphImpl const * pParagraph, |
| ::sal_Int32 nLineNo ) |
| { |
| ::css::i18n::Boundary aBoundary; |
| aBoundary.startPos = 0; |
| aBoundary.endPos = 0; |
| |
| ::osl::Guard< ::comphelper::IMutex > aExternalGuard( getExternalLock() ); |
| { |
| ::osl::MutexGuard aInternalGuard( GetMutex() ); |
| ::sal_uLong nNumber = static_cast< ::sal_uLong >( pParagraph->getNumber() ); |
| if ( nLineNo >= m_rEngine.GetLineCount( nNumber ) ) |
| throw ::css::lang::IndexOutOfBoundsException( |
| ::rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM( |
| "textwindowaccessibility.cxx:" |
| " Document::retrieveParagraphBoundaryOfLine" ) ), |
| static_cast< ::css::uno::XWeak * >( this ) ); |
| ::sal_Int32 nLineStart = 0; |
| ::sal_Int32 nLineEnd = 0; |
| for ( ::sal_uInt16 nLine = 0; nLine <= nLineNo; ++nLine ) |
| { |
| ::sal_Int32 nLineLength = static_cast< ::sal_Int32 >( |
| m_rEngine.GetLineLen( nNumber, nLine ) ); |
| nLineStart = nLineEnd; |
| nLineEnd += nLineLength; |
| } |
| |
| aBoundary.startPos = nLineStart; |
| aBoundary.endPos = nLineEnd; |
| } |
| |
| return aBoundary; |
| } |
| |
| sal_Int32 Document::retrieveParagraphLineWithCursor( ParagraphImpl const * pParagraph ) |
| { |
| ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock()); |
| ::osl::MutexGuard aInternalGuard(GetMutex()); |
| ::TextSelection const & rSelection = m_rView.GetSelection(); |
| Paragraphs::size_type nNumber = pParagraph->getNumber(); |
| TextPaM aEndPaM( rSelection.GetEnd() ); |
| |
| return aEndPaM.GetPara() == nNumber |
| ? m_rView.GetLineNumberOfCursorInSelection() : -1; |
| } |
| |
| |
| ::css::uno::Reference< ::css::accessibility::XAccessibleRelationSet > |
| Document::retrieveParagraphRelationSet( ParagraphImpl const * pParagraph ) |
| { |
| ::osl::MutexGuard aInternalGuard( GetMutex() ); |
| |
| ::utl::AccessibleRelationSetHelper* pRelationSetHelper = new ::utl::AccessibleRelationSetHelper(); |
| ::css::uno::Reference< ::css::accessibility::XAccessibleRelationSet > xSet = pRelationSetHelper; |
| |
| Paragraphs::iterator aPara( m_xParagraphs->begin() + pParagraph->getNumber() ); |
| |
| if ( aPara > m_aVisibleBegin && aPara < m_aVisibleEnd ) |
| { |
| ::css::uno::Sequence< ::css::uno::Reference< ::css::uno::XInterface > > aSequence(1); |
| aSequence[0] = getAccessibleChild( aPara - 1 ); |
| ::css::accessibility::AccessibleRelation aRelation( ::css::accessibility::AccessibleRelationType::CONTENT_FLOWS_FROM, aSequence ); |
| pRelationSetHelper->AddRelation( aRelation ); |
| } |
| |
| if ( aPara >= m_aVisibleBegin && aPara < m_aVisibleEnd -1 ) |
| { |
| ::css::uno::Sequence< ::css::uno::Reference< ::css::uno::XInterface > > aSequence(1); |
| aSequence[0] = getAccessibleChild( aPara + 1 ); |
| ::css::accessibility::AccessibleRelation aRelation( ::css::accessibility::AccessibleRelationType::CONTENT_FLOWS_TO, aSequence ); |
| pRelationSetHelper->AddRelation( aRelation ); |
| } |
| |
| return xSet; |
| } |
| |
| void Document::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent ) |
| { |
| VCLXAccessibleComponent::ProcessWindowEvent( rVclWindowEvent ); |
| } |
| |
| // virtual |
| ::sal_Int32 SAL_CALL Document::getAccessibleChildCount() |
| throw (::css::uno::RuntimeException) |
| { |
| ::comphelper::OExternalLockGuard aGuard(this); |
| init(); |
| return m_aVisibleEnd - m_aVisibleBegin; |
| } |
| |
| // virtual |
| ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL |
| Document::getAccessibleChild(::sal_Int32 i) |
| throw (::css::lang::IndexOutOfBoundsException, |
| ::css::uno::RuntimeException) |
| { |
| ::comphelper::OExternalLockGuard aGuard(this); |
| init(); |
| if (i < 0 || i >= m_aVisibleEnd - m_aVisibleBegin) |
| throw ::css::lang::IndexOutOfBoundsException( |
| ::rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM( |
| "textwindowaccessibility.cxx:" |
| " Document::getAccessibleChild")), |
| static_cast< ::css::uno::XWeak * >(this)); |
| return getAccessibleChild(m_aVisibleBegin |
| + static_cast< Paragraphs::size_type >(i)); |
| } |
| |
| // virtual |
| ::sal_Int16 SAL_CALL Document::getAccessibleRole() |
| throw (::css::uno::RuntimeException) |
| { |
| return ::css::accessibility::AccessibleRole::TEXT_FRAME; |
| } |
| |
| // virtual |
| ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL |
| Document::getAccessibleAtPoint(::css::awt::Point const & rPoint) |
| throw (::css::uno::RuntimeException) |
| { |
| ::comphelper::OExternalLockGuard aGuard(this); |
| init(); |
| if (rPoint.X >= 0 |
| && rPoint.X < m_rView.GetWindow()->GetOutputSizePixel().Width() |
| && rPoint.Y >= 0 && rPoint.Y < m_nViewHeight) |
| { |
| ::sal_Int32 nOffset = m_nViewOffset + rPoint.Y; // XXX numeric overflow |
| ::sal_Int32 nPos = m_nViewOffset - m_nVisibleBeginOffset; |
| for (Paragraphs::iterator aIt(m_aVisibleBegin); aIt != m_aVisibleEnd; |
| ++aIt) |
| { |
| nPos += aIt->getHeight(); // XXX numeric overflow |
| if (nOffset < nPos) |
| return getAccessibleChild(aIt); |
| } |
| } |
| return 0; |
| } |
| void Document::FillAccessibleStateSet( utl::AccessibleStateSetHelper& rStateSet ) |
| { |
| VCLXAccessibleComponent::FillAccessibleStateSet( rStateSet ); |
| if (!m_rView.IsReadOnly()) |
| rStateSet.AddState( ::css::accessibility::AccessibleStateType::EDITABLE ); |
| } |
| |
| void Document::FillAccessibleRelationSet( utl::AccessibleRelationSetHelper& rRelationSet ) |
| { |
| if( getAccessibleParent()->getAccessibleContext()->getAccessibleRole() == ::css::accessibility::AccessibleRole::SCROLL_PANE ) |
| { |
| ::css::uno::Sequence< ::css::uno::Reference< ::css::uno::XInterface > > aSequence(1); |
| aSequence[0] = getAccessibleParent(); |
| rRelationSet.AddRelation( ::css::accessibility::AccessibleRelation( ::css::accessibility::AccessibleRelationType::MEMBER_OF, aSequence ) ); |
| } |
| else |
| { |
| VCLXAccessibleComponent::FillAccessibleRelationSet(rRelationSet); |
| } |
| } |
| // virtual |
| void SAL_CALL Document::disposing() |
| { |
| m_aEngineListener.endListening(); |
| m_aViewListener.endListening(); |
| if (m_xParagraphs.get() != 0) |
| disposeParagraphs(); |
| VCLXAccessibleComponent::disposing(); |
| } |
| |
| // virtual |
| void Document::Notify(::SfxBroadcaster &, ::SfxHint const & rHint) |
| { |
| if (rHint.ISA(::TextHint)) |
| { |
| ::TextHint const & rTextHint |
| = static_cast< ::TextHint const & >(rHint); |
| switch (rTextHint.GetId()) |
| { |
| case TEXT_HINT_PARAINSERTED: |
| case TEXT_HINT_PARAREMOVED: |
| // TEXT_HINT_PARAINSERTED and TEXT_HINT_PARAREMOVED are sent at |
| // "unsafe" times (when the text engine has not yet re-formatted its |
| // content), so that for example calling ::TextEngine::GetTextHeight |
| // from within the code that handles TEXT_HINT_PARAINSERTED causes |
| // trouble within the text engine. Therefore, these hints are just |
| // buffered until a following ::TextEngine::FormatDoc causes a |
| // TEXT_HINT_TEXTFORMATTED to come in: |
| case TEXT_HINT_FORMATPARA: |
| // ::TextEngine::FormatDoc sends a sequence of |
| // TEXT_HINT_FORMATPARAs, followed by an optional |
| // TEXT_HINT_TEXTHEIGHTCHANGED, followed in all cases by one |
| // TEXT_HINT_TEXTFORMATTED. Only the TEXT_HINT_FORMATPARAs contain |
| // the the numbers of the affected paragraphs, but they are sent |
| // before the changes are applied. Therefore, TEXT_HINT_FORMATPARAs |
| // are just buffered until another hint comes in: |
| { |
| ::osl::MutexGuard aInternalGuard(GetMutex()); |
| if (!isAlive()) |
| break; |
| |
| m_aParagraphNotifications.push(rTextHint); |
| break; |
| } |
| case TEXT_HINT_TEXTFORMATTED: |
| case TEXT_HINT_TEXTHEIGHTCHANGED: |
| case TEXT_HINT_MODIFIED: |
| { |
| ::osl::MutexGuard aInternalGuard(GetMutex()); |
| if (!isAlive()) |
| break; |
| handleParagraphNotifications(); |
| break; |
| } |
| case TEXT_HINT_VIEWSCROLLED: |
| { |
| ::osl::MutexGuard aInternalGuard(GetMutex()); |
| if (!isAlive()) |
| break; |
| handleParagraphNotifications(); |
| |
| ::sal_Int32 nOffset = static_cast< ::sal_Int32 >( |
| m_rView.GetStartDocPos().Y()); |
| // XXX numeric overflow |
| if (nOffset != m_nViewOffset) |
| { |
| m_nViewOffset = nOffset; |
| |
| Paragraphs::iterator aOldVisibleBegin( |
| m_aVisibleBegin); |
| Paragraphs::iterator aOldVisibleEnd(m_aVisibleEnd); |
| |
| determineVisibleRange(); |
| |
| notifyVisibleRangeChanges(aOldVisibleBegin, |
| aOldVisibleEnd, |
| m_xParagraphs->end()); |
| } |
| break; |
| } |
| case TEXT_HINT_VIEWSELECTIONCHANGED: |
| { |
| ::osl::MutexGuard aInternalGuard(GetMutex()); |
| if (!isAlive()) |
| break; |
| |
| if (m_aParagraphNotifications.empty()) |
| { |
| handleSelectionChangeNotification(); |
| } |
| else |
| { |
| // TEXT_HINT_VIEWSELECTIONCHANGED is sometimes sent at |
| // "unsafe" times (when the text engine has not yet re- |
| // formatted its content), so that for example calling |
| // ::TextEngine::GetTextHeight from within the code that |
| // handles a previous TEXT_HINT_PARAINSERTED causes |
| // trouble within the text engine. Therefore, these |
| // hints are just buffered (along with |
| // TEXT_HINT_PARAINSERTED/REMOVED/FORMATPARA) until a |
| // following ::TextEngine::FormatDoc causes a |
| // TEXT_HINT_TEXTFORMATTED to come in: |
| m_bSelectionChangedNotification = true; |
| } |
| break; |
| } |
| } |
| } |
| } |
| |
| IMPL_LINK(Document, WindowEventHandler, ::VclSimpleEvent *, pEvent) |
| { |
| switch (pEvent->GetId()) |
| { |
| case VCLEVENT_WINDOW_RESIZE: |
| { |
| ::osl::MutexGuard aInternalGuard(GetMutex()); |
| if (!isAlive()) |
| break; |
| |
| ::sal_Int32 nHeight = static_cast< ::sal_Int32 >( |
| m_rView.GetWindow()->GetOutputSizePixel().Height()); |
| // XXX numeric overflow |
| if (nHeight != m_nViewHeight) |
| { |
| m_nViewHeight = nHeight; |
| |
| Paragraphs::iterator aOldVisibleBegin(m_aVisibleBegin); |
| Paragraphs::iterator aOldVisibleEnd(m_aVisibleEnd); |
| |
| determineVisibleRange(); |
| |
| notifyVisibleRangeChanges(aOldVisibleBegin, aOldVisibleEnd, |
| m_xParagraphs->end()); |
| } |
| break; |
| } |
| case VCLEVENT_WINDOW_GETFOCUS: |
| { |
| ::osl::MutexGuard aInternalGuard(GetMutex()); |
| if (!isAlive()) |
| break; |
| //to enable the PARAGRAPH to get focus for multiline edit |
| ::sal_Int32 count = getAccessibleChildCount(); |
| ::sal_Bool bEmpty = m_aFocused == m_aVisibleEnd && count == 1; |
| if ((m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd) || bEmpty) |
| { |
| Paragraphs::iterator m_aTemp = bEmpty ? m_aVisibleBegin : m_aFocused; |
| ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(m_aTemp)); |
| if (xParagraph.is()) |
| { |
| xParagraph->notifyEvent( |
| ::css::accessibility::AccessibleEventId:: |
| STATE_CHANGED, |
| ::css::uno::Any(), |
| ::css::uno::makeAny( |
| ::css::accessibility::AccessibleStateType:: |
| FOCUSED)); |
| } |
| } |
| /* |
| ::rtl::Reference< ParagraphImpl > xParagraph( |
| getParagraph(m_aFocused)); |
| if (xParagraph.is()) |
| xParagraph->notifyEvent( |
| ::css::accessibility::AccessibleEventId:: |
| STATE_CHANGED, |
| ::css::uno::Any(), |
| ::css::uno::makeAny( |
| ::css::accessibility::AccessibleStateType:: |
| FOCUSED)); |
| */ |
| break; |
| } |
| case VCLEVENT_WINDOW_LOSEFOCUS: |
| { |
| ::osl::MutexGuard aInternalGuard(GetMutex()); |
| if (!isAlive()) |
| break; |
| //to enable the PARAGRAPH to get focus for multiline edit |
| ::sal_Int32 count = getAccessibleChildCount(); |
| ::sal_Bool bEmpty = m_aFocused == m_aVisibleEnd && count == 1; |
| if ((m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd) || bEmpty) |
| { |
| Paragraphs::iterator m_aTemp = bEmpty ? m_aVisibleBegin : m_aFocused; |
| ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(m_aTemp)); |
| if (xParagraph.is()) |
| xParagraph->notifyEvent( |
| ::css::accessibility::AccessibleEventId:: |
| STATE_CHANGED, |
| ::css::uno::makeAny( |
| ::css::accessibility::AccessibleStateType:: |
| FOCUSED), |
| ::css::uno::Any()); |
| } |
| |
| /* |
| if (m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd) |
| { |
| ::rtl::Reference< ParagraphImpl > xParagraph( |
| getParagraph(m_aFocused)); |
| if (xParagraph.is()) |
| xParagraph->notifyEvent( |
| ::css::accessibility::AccessibleEventId:: |
| STATE_CHANGED, |
| ::css::uno::makeAny( |
| ::css::accessibility::AccessibleStateType:: |
| FOCUSED), |
| ::css::uno::Any()); |
| } |
| */ |
| break; |
| } |
| } |
| return 0; |
| } |
| |
| void Document::init() |
| { |
| if (m_xParagraphs.get() == 0) |
| { |
| ::sal_uLong nCount = m_rEngine.GetParagraphCount(); |
| ::std::auto_ptr< Paragraphs > p(new Paragraphs); |
| p->reserve(static_cast< Paragraphs::size_type >(nCount)); |
| // numeric overflow is harmless here |
| for (::sal_uLong i = 0; i < nCount; ++i) |
| p->push_back(ParagraphInfo(static_cast< ::sal_Int32 >( |
| m_rEngine.GetTextHeight(i)))); |
| // XXX numeric overflow |
| m_nViewOffset = static_cast< ::sal_Int32 >( |
| m_rView.GetStartDocPos().Y()); // XXX numeric overflow |
| m_nViewHeight = static_cast< ::sal_Int32 >( |
| m_rView.GetWindow()->GetOutputSizePixel().Height()); |
| // XXX numeric overflow |
| m_xParagraphs = p; |
| determineVisibleRange(); |
| m_nSelectionFirstPara = -1; |
| m_nSelectionFirstPos = -1; |
| m_nSelectionLastPara = -1; |
| m_nSelectionLastPos = -1; |
| m_aFocused = m_xParagraphs->end(); |
| m_bSelectionChangedNotification = false; |
| m_aEngineListener.startListening(m_rEngine); |
| m_aViewListener.startListening(*m_rView.GetWindow()); |
| } |
| } |
| |
| ::rtl::Reference< ParagraphImpl > |
| Document::getParagraph(Paragraphs::iterator const & rIt) |
| { |
| return static_cast< ParagraphImpl * >( |
| ::css::uno::Reference< ::css::accessibility::XAccessible >( |
| rIt->getParagraph()).get()); |
| } |
| |
| ::css::uno::Reference< ::css::accessibility::XAccessible > |
| Document::getAccessibleChild(Paragraphs::iterator const & rIt) |
| { |
| ::css::uno::Reference< ::css::accessibility::XAccessible > xParagraph( |
| rIt->getParagraph()); |
| if (!xParagraph.is()) |
| { |
| xParagraph = new Paragraph(this, rIt - m_xParagraphs->begin()); |
| rIt->setParagraph(xParagraph); |
| } |
| return xParagraph; |
| } |
| |
| void Document::determineVisibleRange() |
| { |
| m_aVisibleBegin = m_xParagraphs->end(); |
| m_aVisibleEnd = m_aVisibleBegin; |
| ::sal_Int32 nPos = 0; |
| for (Paragraphs::iterator aIt = m_xParagraphs->begin();;) |
| { |
| if (aIt == m_xParagraphs->end()) |
| { |
| m_nVisibleBeginOffset = 0; |
| break; |
| } |
| ::sal_Int32 nOldPos = nPos; |
| nPos += aIt->getHeight(); // XXX numeric overflow |
| if (m_aVisibleBegin == m_xParagraphs->end() && nPos >= m_nViewOffset) |
| { |
| m_aVisibleBegin = aIt; |
| m_nVisibleBeginOffset = m_nViewOffset - nOldPos; |
| } |
| ++aIt; |
| if (m_aVisibleBegin != m_xParagraphs->end() |
| && (aIt == m_xParagraphs->end() |
| || nPos >= m_nViewOffset + m_nViewHeight)) |
| // XXX numeric overflow |
| { |
| m_aVisibleEnd = aIt; |
| break; |
| } |
| } |
| } |
| |
| void Document::notifyVisibleRangeChanges( |
| Paragraphs::iterator const & rOldVisibleBegin, |
| Paragraphs::iterator const & rOldVisibleEnd, |
| Paragraphs::iterator const & rInserted) |
| { |
| // XXX Replace this code that determines which paragraphs have changed from |
| // invisible to visible or vice versa with a better algorithm. |
| {for (Paragraphs::iterator aIt(rOldVisibleBegin); aIt != rOldVisibleEnd; |
| ++aIt) |
| if (aIt != rInserted |
| && (aIt < m_aVisibleBegin || aIt >= m_aVisibleEnd)) |
| NotifyAccessibleEvent( |
| ::css::accessibility::AccessibleEventId:: |
| CHILD, |
| ::css::uno::makeAny(getAccessibleChild(aIt)), |
| ::css::uno::Any()); |
| } |
| {for (Paragraphs::iterator aIt(m_aVisibleBegin); aIt != m_aVisibleEnd; |
| ++aIt) |
| if (aIt == rInserted |
| || aIt < rOldVisibleBegin || aIt >= rOldVisibleEnd) |
| NotifyAccessibleEvent( |
| ::css::accessibility::AccessibleEventId:: |
| CHILD, |
| ::css::uno::Any(), |
| ::css::uno::makeAny(getAccessibleChild(aIt))); |
| } |
| } |
| |
| void |
| Document::changeParagraphText(::sal_uLong nNumber, ::sal_uInt16 nBegin, ::sal_uInt16 nEnd, |
| bool bCut, bool bPaste, |
| ::rtl::OUString const & rText) |
| { |
| m_rView.SetSelection(::TextSelection(::TextPaM(nNumber, nBegin), |
| ::TextPaM(nNumber, nEnd))); |
| if (bCut) |
| m_rView.Cut(); |
| else if (nBegin != nEnd) |
| m_rView.DeleteSelected(); |
| if (bPaste) |
| m_rView.Paste(); |
| else if ( !rText.isEmpty() ) |
| m_rView.InsertText(rText); |
| } |
| |
| void Document::handleParagraphNotifications() |
| { |
| while (!m_aParagraphNotifications.empty()) |
| { |
| ::TextHint aHint(m_aParagraphNotifications.front()); |
| m_aParagraphNotifications.pop(); |
| switch (aHint.GetId()) |
| { |
| case TEXT_HINT_PARAINSERTED: |
| { |
| ::sal_uLong n = aHint.GetValue(); |
| OSL_ENSURE(n <= m_xParagraphs->size(), |
| "bad TEXT_HINT_PARAINSERTED event"); |
| |
| // Save the values of old iterators (the iterators themselves |
| // will get invalidated), and adjust the old values so that they |
| // reflect the insertion of the new paragraph: |
| Paragraphs::size_type nOldVisibleBegin |
| = m_aVisibleBegin - m_xParagraphs->begin(); |
| Paragraphs::size_type nOldVisibleEnd |
| = m_aVisibleEnd - m_xParagraphs->begin(); |
| Paragraphs::size_type nOldFocused |
| = m_aFocused - m_xParagraphs->begin(); |
| if (n <= nOldVisibleBegin) |
| ++nOldVisibleBegin; // XXX numeric overflow |
| if (n <= nOldVisibleEnd) |
| ++nOldVisibleEnd; // XXX numeric overflow |
| if (n <= nOldFocused) |
| ++nOldFocused; // XXX numeric overflow |
| if (sal::static_int_cast<sal_Int32>(n) <= m_nSelectionFirstPara) |
| ++m_nSelectionFirstPara; // XXX numeric overflow |
| if (sal::static_int_cast<sal_Int32>(n) <= m_nSelectionLastPara) |
| ++m_nSelectionLastPara; // XXX numeric overflow |
| |
| Paragraphs::iterator aIns( |
| m_xParagraphs->insert( |
| m_xParagraphs->begin() + n, |
| ParagraphInfo(static_cast< ::sal_Int32 >( |
| m_rEngine.GetTextHeight(n))))); |
| // XXX numeric overflow (2x) |
| |
| determineVisibleRange(); |
| m_aFocused = m_xParagraphs->begin() + nOldFocused; |
| |
| for (Paragraphs::iterator aIt(aIns);;) |
| { |
| ++aIt; |
| if (aIt == m_xParagraphs->end()) |
| break; |
| ::rtl::Reference< ParagraphImpl > xParagraph( |
| getParagraph(aIt)); |
| if (xParagraph.is()) |
| xParagraph->numberChanged(true); |
| } |
| |
| notifyVisibleRangeChanges( |
| m_xParagraphs->begin() + nOldVisibleBegin, |
| m_xParagraphs->begin() + nOldVisibleEnd, aIns); |
| break; |
| } |
| case TEXT_HINT_PARAREMOVED: |
| { |
| ::sal_uLong n = aHint.GetValue(); |
| if (n == TEXT_PARA_ALL) |
| { |
| {for (Paragraphs::iterator aIt(m_aVisibleBegin); |
| aIt != m_aVisibleEnd; ++aIt) |
| NotifyAccessibleEvent( |
| ::css::accessibility::AccessibleEventId:: |
| CHILD, |
| ::css::uno::makeAny(getAccessibleChild(aIt)), |
| ::css::uno::Any()); |
| } |
| disposeParagraphs(); |
| m_xParagraphs->clear(); |
| determineVisibleRange(); |
| m_nSelectionFirstPara = -1; |
| m_nSelectionFirstPos = -1; |
| m_nSelectionLastPara = -1; |
| m_nSelectionLastPos = -1; |
| m_aFocused = m_xParagraphs->end(); |
| } |
| else |
| { |
| OSL_ENSURE(n < m_xParagraphs->size(), |
| "Bad TEXT_HINT_PARAREMOVED event"); |
| |
| Paragraphs::iterator aIt(m_xParagraphs->begin() + n); |
| // numeric overflow cannot occur |
| |
| // Save the values of old iterators (the iterators |
| // themselves will get invalidated), and adjust the old |
| // values so that they reflect the removal of the paragraph: |
| Paragraphs::size_type nOldVisibleBegin |
| = m_aVisibleBegin - m_xParagraphs->begin(); |
| Paragraphs::size_type nOldVisibleEnd |
| = m_aVisibleEnd - m_xParagraphs->begin(); |
| bool bWasVisible |
| = nOldVisibleBegin <= n && n < nOldVisibleEnd; |
| Paragraphs::size_type nOldFocused |
| = m_aFocused - m_xParagraphs->begin(); |
| bool bWasFocused = aIt == m_aFocused; |
| if (n < nOldVisibleBegin) |
| --nOldVisibleBegin; |
| if (n < nOldVisibleEnd) |
| --nOldVisibleEnd; |
| if (n < nOldFocused) |
| --nOldFocused; |
| if (sal::static_int_cast<sal_Int32>(n) < m_nSelectionFirstPara) |
| --m_nSelectionFirstPara; |
| else if (sal::static_int_cast<sal_Int32>(n) == m_nSelectionFirstPara) |
| { |
| if (m_nSelectionFirstPara == m_nSelectionLastPara) |
| { |
| m_nSelectionFirstPara = -1; |
| m_nSelectionFirstPos = -1; |
| m_nSelectionLastPara = -1; |
| m_nSelectionLastPos = -1; |
| } |
| else |
| { |
| ++m_nSelectionFirstPara; |
| m_nSelectionFirstPos = 0; |
| } |
| } |
| if (sal::static_int_cast<sal_Int32>(n) < m_nSelectionLastPara) |
| --m_nSelectionLastPara; |
| else if (sal::static_int_cast<sal_Int32>(n) == m_nSelectionLastPara) |
| { |
| OSL_ENSURE(m_nSelectionFirstPara < m_nSelectionLastPara, |
| "logic error"); |
| --m_nSelectionLastPara; |
| m_nSelectionLastPos = 0x7FFFFFFF; |
| } |
| |
| ::css::uno::Reference< ::css::accessibility::XAccessible > |
| xStrong; |
| if (bWasVisible) |
| xStrong = getAccessibleChild(aIt); |
| ::css::uno::WeakReference< |
| ::css::accessibility::XAccessible > xWeak( |
| aIt->getParagraph()); |
| aIt = m_xParagraphs->erase(aIt); |
| |
| determineVisibleRange(); |
| m_aFocused = bWasFocused ? m_xParagraphs->end() |
| : m_xParagraphs->begin() + nOldFocused; |
| |
| for (; aIt != m_xParagraphs->end(); ++aIt) |
| { |
| ::rtl::Reference< ParagraphImpl > xParagraph( |
| getParagraph(aIt)); |
| if (xParagraph.is()) |
| xParagraph->numberChanged(false); |
| } |
| |
| if (bWasVisible) |
| NotifyAccessibleEvent( |
| ::css::accessibility::AccessibleEventId:: |
| CHILD, |
| ::css::uno::makeAny(getAccessibleChild(aIt)), |
| ::css::uno::Any()); |
| |
| ::css::uno::Reference< ::css::lang::XComponent > xComponent( |
| xWeak.get(), ::css::uno::UNO_QUERY); |
| if (xComponent.is()) |
| xComponent->dispose(); |
| |
| notifyVisibleRangeChanges( |
| m_xParagraphs->begin() + nOldVisibleBegin, |
| m_xParagraphs->begin() + nOldVisibleEnd, |
| m_xParagraphs->end()); |
| } |
| break; |
| } |
| case TEXT_HINT_FORMATPARA: |
| { |
| ::sal_uLong n = aHint.GetValue(); |
| OSL_ENSURE(n < m_xParagraphs->size(), |
| "Bad TEXT_HINT_FORMATPARA event"); |
| |
| (*m_xParagraphs)[static_cast< Paragraphs::size_type >(n)]. |
| changeHeight(static_cast< ::sal_Int32 >( |
| m_rEngine.GetTextHeight(n))); |
| // XXX numeric overflow |
| Paragraphs::iterator aOldVisibleBegin(m_aVisibleBegin); |
| Paragraphs::iterator aOldVisibleEnd(m_aVisibleEnd); |
| determineVisibleRange(); |
| notifyVisibleRangeChanges(aOldVisibleBegin, aOldVisibleEnd, |
| m_xParagraphs->end()); |
| |
| if (n < m_xParagraphs->size()) |
| { |
| Paragraphs::iterator aIt(m_xParagraphs->begin() + n); |
| ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(aIt)); |
| if (xParagraph.is()) |
| xParagraph->textChanged(); |
| } |
| break; |
| } |
| default: |
| OSL_ENSURE(false, "bad buffered hint"); |
| break; |
| } |
| } |
| if (m_bSelectionChangedNotification) |
| { |
| m_bSelectionChangedNotification = false; |
| handleSelectionChangeNotification(); |
| } |
| } |
| |
| ::sal_Int32 Document::getSelectionType(::sal_Int32 nNewFirstPara, ::sal_Int32 nNewFirstPos, ::sal_Int32 nNewLastPara, ::sal_Int32 nNewLastPos) |
| { |
| if (m_nSelectionFirstPara == -1) |
| return -1; |
| ::sal_Int32 Osp = m_nSelectionFirstPara, Osl = m_nSelectionFirstPos, Oep = m_nSelectionLastPara, Oel = m_nSelectionLastPos; |
| ::sal_Int32 Nsp = nNewFirstPara, Nsl = nNewFirstPos, Nep = nNewLastPara, Nel = nNewLastPos; |
| TextPaM Ns(Nsp, sal_uInt16(Nsl)); |
| TextPaM Ne(Nep, sal_uInt16(Nel)); |
| TextPaM Os(Osp, sal_uInt16(Osl)); |
| TextPaM Oe(Oep, sal_uInt16(Oel)); |
| |
| if (Os == Oe && Ns == Ne) |
| { |
| //only caret moves. |
| return 1; |
| } |
| else if (Os == Oe && Ns != Ne) |
| { |
| //old has no selection but new has selection |
| return 2; |
| } |
| else if (Os != Oe && Ns == Ne) |
| { |
| //old has selection but new has no selection. |
| return 3; |
| } |
| else if (Os != Oe && Ns != Ne && Osp == Nsp && Osl == Nsl) |
| { |
| //both old and new have selections. |
| if (Oep == Nep ) |
| { |
| //Send text_selection_change event on Nep |
| |
| return 4; |
| } |
| else if (Oep < Nep) |
| { |
| //all the following examples like 1,2->1,3 means that old start select para is 1, old end select para is 2, |
| // then press shift up, the new start select para is 1, new end select para is 3; |
| //for example, 1, 2 -> 1, 3; 4,1 -> 4, 7; 4,1 -> 4, 2; 4,4->4,5 |
| if (Nep >= Nsp) |
| { |
| // 1, 2 -> 1, 3; 4, 1 -> 4, 7; 4,4->4,5; |
| if (Oep < Osp) |
| { |
| // 4,1 -> 4,7; |
| return 5; |
| } |
| else if (Oep >= Osp) |
| { |
| // 1, 2 -> 1, 3; 4,4->4,5; |
| return 6; |
| } |
| } |
| else |
| { |
| // 4,1 -> 4,2, |
| if (Oep < Osp) |
| { |
| // 4,1 -> 4,2, |
| return 7; |
| } |
| else if (Oep >= Osp) |
| { |
| // no such condition. Oep > Osp = Nsp > Nep |
| } |
| } |
| } |
| else if (Oep > Nep) |
| { |
| // 3,2 -> 3,1; 4,7 -> 4,1; 4, 7 -> 4,6; 4,4 -> 4,3 |
| if (Nep >= Nsp) |
| { |
| // 4,7 -> 4,6 |
| if (Oep <= Osp) |
| { |
| //no such condition, Oep<Osp=Nsp <= Nep |
| } |
| else if (Oep > Osp) |
| { |
| // 4,7 ->4,6 |
| return 8; |
| } |
| } |
| else |
| { |
| // 3,2 -> 3,1, 4,7 -> 4,1; 4,4->4,3 |
| if (Oep <= Osp) |
| { |
| // 3,2 -> 3,1; 4,4->4,3 |
| return 9; |
| } |
| else if (Oep > Osp) |
| { |
| // 4,7 -> 4,1 |
| return 10; |
| } |
| } |
| } |
| } |
| return -1; |
| } |
| |
| |
| void Document::sendEvent(::sal_Int32 start, ::sal_Int32 end, ::sal_Int16 nEventId) |
| { |
| Paragraphs::iterator aEnd = ::std::min(m_xParagraphs->begin() + end + 1, m_aVisibleEnd); |
| for (Paragraphs::iterator aIt = ::std::max(m_xParagraphs->begin() + start, m_aVisibleBegin); |
| aIt < aEnd; ++aIt) |
| { |
| ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(aIt)); |
| if (xParagraph.is()) |
| xParagraph->notifyEvent( |
| nEventId, |
| ::css::uno::Any(), ::css::uno::Any()); |
| } |
| } |
| |
| void Document::handleSelectionChangeNotification() |
| { |
| ::TextSelection const & rSelection = m_rView.GetSelection(); |
| OSL_ENSURE(rSelection.GetStart().GetPara() < m_xParagraphs->size() |
| && rSelection.GetEnd().GetPara() < m_xParagraphs->size(), |
| "bad TEXT_HINT_VIEWSELECTIONCHANGED event"); |
| ::sal_Int32 nNewFirstPara |
| = static_cast< ::sal_Int32 >(rSelection.GetStart().GetPara()); |
| ::sal_Int32 nNewFirstPos |
| = static_cast< ::sal_Int32 >(rSelection.GetStart().GetIndex()); |
| // XXX numeric overflow |
| ::sal_Int32 nNewLastPara |
| = static_cast< ::sal_Int32 >(rSelection.GetEnd().GetPara()); |
| ::sal_Int32 nNewLastPos |
| = static_cast< ::sal_Int32 >(rSelection.GetEnd().GetIndex()); |
| // XXX numeric overflow |
| |
| // Lose focus: |
| Paragraphs::iterator aIt(m_xParagraphs->begin() + nNewLastPara); |
| if (m_aFocused != m_xParagraphs->end() && m_aFocused != aIt |
| && m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd) |
| { |
| ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(m_aFocused)); |
| if (xParagraph.is()) |
| xParagraph->notifyEvent( |
| ::css::accessibility::AccessibleEventId:: |
| STATE_CHANGED, |
| ::css::uno::makeAny( |
| ::css::accessibility::AccessibleStateType::FOCUSED), |
| ::css::uno::Any()); |
| } |
| |
| // Gain focus and update cursor position: |
| if (aIt >= m_aVisibleBegin && aIt < m_aVisibleEnd |
| && (aIt != m_aFocused |
| || nNewLastPara != m_nSelectionLastPara |
| || nNewLastPos != m_nSelectionLastPos)) |
| { |
| ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(aIt)); |
| if (xParagraph.is()) |
| { |
| //disable the first event when user types in empty field. |
| ::sal_Int32 count = getAccessibleChildCount(); |
| ::sal_Bool bEmpty = count > 1; |
| //if (aIt != m_aFocused) |
| if (aIt != m_aFocused && bEmpty) |
| xParagraph->notifyEvent( |
| ::css::accessibility::AccessibleEventId:: |
| STATE_CHANGED, |
| ::css::uno::Any(), |
| ::css::uno::makeAny( |
| ::css::accessibility::AccessibleStateType::FOCUSED)); |
| if (nNewLastPara != m_nSelectionLastPara |
| || nNewLastPos != m_nSelectionLastPos) |
| xParagraph->notifyEvent( |
| ::css::accessibility::AccessibleEventId:: |
| CARET_CHANGED, |
| ::css::uno::makeAny< ::sal_Int32 >( |
| nNewLastPara == m_nSelectionLastPara |
| ? m_nSelectionLastPos : 0), |
| ::css::uno::makeAny(nNewLastPos)); |
| } |
| } |
| m_aFocused = aIt; |
| |
| ::sal_Int32 nMin; |
| ::sal_Int32 nMax; |
| ::sal_Int32 ret = getSelectionType(nNewFirstPara, nNewFirstPos, nNewLastPara, nNewLastPos); |
| switch (ret) |
| { |
| case -1: |
| { |
| //no event |
| } |
| break; |
| case 1: |
| { |
| //only caret moved, already handled in above |
| } |
| break; |
| case 2: |
| { |
| //old has no selection but new has selection |
| nMin = ::std::min(nNewFirstPara, nNewLastPara); |
| nMax = ::std::max(nNewFirstPara, nNewLastPara); |
| sendEvent(nMin, nMax, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); |
| sendEvent(nMin, nMax, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); |
| } |
| break; |
| case 3: |
| { |
| //old has selection but new has no selection. |
| nMin = ::std::min(m_nSelectionFirstPara, m_nSelectionLastPara); |
| nMax = ::std::max(m_nSelectionFirstPara, m_nSelectionLastPara); |
| sendEvent(nMin, nMax, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); |
| sendEvent(nMin, nMax, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); |
| } |
| break; |
| case 4: |
| { |
| //Send text_selection_change event on Nep |
| sendEvent(nNewLastPara, nNewLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); |
| } |
| break; |
| case 5: |
| { |
| // 4, 1 -> 4, 7 |
| sendEvent(m_nSelectionLastPara, m_nSelectionFirstPara-1, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); |
| sendEvent(nNewFirstPara+1, nNewLastPara, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); |
| |
| sendEvent(m_nSelectionLastPara, nNewLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); |
| } |
| break; |
| case 6: |
| { |
| // 1, 2 -> 1, 4; 4,4->4,5; |
| sendEvent(m_nSelectionLastPara+1, nNewLastPara, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); |
| |
| sendEvent(m_nSelectionLastPara, nNewLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); |
| } |
| break; |
| case 7: |
| { |
| // 4,1 -> 4,3, |
| sendEvent(m_nSelectionLastPara +1, nNewLastPara , ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); |
| |
| sendEvent(m_nSelectionLastPara, nNewLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); |
| } |
| break; |
| case 8: |
| { |
| // 4,7 ->4,5; |
| sendEvent(nNewLastPara + 1, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); |
| |
| sendEvent(nNewLastPara, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); |
| } |
| break; |
| case 9: |
| { |
| // 3,2 -> 3,1; 4,4->4,3 |
| sendEvent(nNewLastPara, m_nSelectionLastPara - 1, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); |
| |
| sendEvent(nNewLastPara, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); |
| } |
| break; |
| case 10: |
| { |
| // 4,7 -> 4,1 |
| sendEvent(m_nSelectionFirstPara + 1, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); |
| sendEvent(nNewLastPara, nNewFirstPara - 1, ::css::accessibility::AccessibleEventId::SELECTION_CHANGED); |
| |
| sendEvent(nNewLastPara, m_nSelectionLastPara, ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED); |
| } |
| break; |
| default: |
| break; |
| } |
| |
| /* |
| // Update both old and new selection. (Regardless of how the two selections |
| // look like, there will always be two ranges to the left and right of the |
| // overlap---the overlap and/or the range to the right of it possibly being |
| // empty. Only for these two ranges notifications have to be sent.) |
| |
| TextPaM aOldTextStart( static_cast< sal_uLong >( m_nSelectionFirstPara ), static_cast< sal_uInt16 >( m_nSelectionFirstPos ) ); |
| TextPaM aOldTextEnd( static_cast< sal_uLong >( m_nSelectionLastPara ), static_cast< sal_uInt16 >( m_nSelectionLastPos ) ); |
| TextPaM aNewTextStart( static_cast< sal_uLong >( nNewFirstPara ), static_cast< sal_uInt16 >( nNewFirstPos ) ); |
| TextPaM aNewTextEnd( static_cast< sal_uLong >( nNewLastPara ), static_cast< sal_uInt16 >( nNewLastPos ) ); |
| |
| // justify selections |
| justifySelection( aOldTextStart, aOldTextEnd ); |
| justifySelection( aNewTextStart, aNewTextEnd ); |
| |
| sal_Int32 nFirst1; |
| sal_Int32 nLast1; |
| sal_Int32 nFirst2; |
| sal_Int32 nLast2; |
| |
| if ( m_nSelectionFirstPara == -1 ) |
| { |
| // old selection not initialized yet => notify events only for new selection (if not empty) |
| nFirst1 = aNewTextStart.GetPara(); |
| nLast1 = aNewTextEnd.GetPara() + ( aNewTextStart != aNewTextEnd ? 1 : 0 ); |
| nFirst2 = 0; |
| nLast2 = 0; |
| } |
| else if ( aOldTextStart == aOldTextEnd && aNewTextStart == aNewTextEnd ) |
| { |
| // old an new selection empty => no events |
| nFirst1 = 0; |
| nLast1 = 0; |
| nFirst2 = 0; |
| nLast2 = 0; |
| } |
| else if ( aOldTextStart != aOldTextEnd && aNewTextStart == aNewTextEnd ) |
| { |
| // old selection not empty + new selection empty => notify events only for old selection |
| nFirst1 = aOldTextStart.GetPara(); |
| nLast1 = aOldTextEnd.GetPara() + 1; |
| nFirst2 = 0; |
| nLast2 = 0; |
| } |
| else if ( aOldTextStart == aOldTextEnd && aNewTextStart != aNewTextEnd ) |
| { |
| // old selection empty + new selection not empty => notify events only for new selection |
| nFirst1 = aNewTextStart.GetPara(); |
| nLast1 = aNewTextEnd.GetPara() + 1; |
| nFirst2 = 0; |
| nLast2 = 0; |
| } |
| else |
| { |
| // old and new selection not empty => notify events for the two ranges left and right of the overlap |
| ::std::vector< TextPaM > aTextPaMs(4); |
| aTextPaMs[0] = aOldTextStart; |
| aTextPaMs[1] = aOldTextEnd; |
| aTextPaMs[2] = aNewTextStart; |
| aTextPaMs[3] = aNewTextEnd; |
| ::std::sort( aTextPaMs.begin(), aTextPaMs.end() ); |
| |
| nFirst1 = aTextPaMs[0].GetPara(); |
| nLast1 = aTextPaMs[1].GetPara() + ( aTextPaMs[0] != aTextPaMs[1] ? 1 : 0 ); |
| |
| nFirst2 = aTextPaMs[2].GetPara(); |
| nLast2 = aTextPaMs[3].GetPara() + ( aTextPaMs[2] != aTextPaMs[3] ? 1 : 0 ); |
| |
| // adjust overlapping ranges |
| if ( nLast1 > nFirst2 ) |
| nLast1 = nFirst2; |
| } |
| |
| // notify selection changes |
| notifySelectionChange( nFirst1, nLast1 ); |
| notifySelectionChange( nFirst2, nLast2 ); |
| */ |
| m_nSelectionFirstPara = nNewFirstPara; |
| m_nSelectionFirstPos = nNewFirstPos; |
| m_nSelectionLastPara = nNewLastPara; |
| m_nSelectionLastPos = nNewLastPos; |
| } |
| |
| void Document::notifySelectionChange( sal_Int32 nFirst, sal_Int32 nLast ) |
| { |
| if ( nFirst < nLast ) |
| { |
| Paragraphs::iterator aEnd( ::std::min( m_xParagraphs->begin() + nLast, m_aVisibleEnd ) ); |
| for ( Paragraphs::iterator aIt = ::std::max( m_xParagraphs->begin() + nFirst, m_aVisibleBegin ); aIt < aEnd; ++aIt ) |
| { |
| ::rtl::Reference< ParagraphImpl > xParagraph( getParagraph( aIt ) ); |
| if ( xParagraph.is() ) |
| { |
| xParagraph->notifyEvent( |
| ::css::accessibility::AccessibleEventId::SELECTION_CHANGED, |
| ::css::uno::Any(), ::css::uno::Any() ); |
| xParagraph->notifyEvent( |
| ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED, |
| ::css::uno::Any(), ::css::uno::Any() ); |
| } |
| } |
| } |
| } |
| |
| void Document::justifySelection( TextPaM& rTextStart, TextPaM& rTextEnd ) |
| { |
| if ( rTextStart > rTextEnd ) |
| { |
| TextPaM aTextPaM( rTextStart ); |
| rTextStart = rTextEnd; |
| rTextEnd = aTextPaM; |
| } |
| } |
| |
| void Document::disposeParagraphs() |
| { |
| for (Paragraphs::iterator aIt(m_xParagraphs->begin()); |
| aIt != m_xParagraphs->end(); ++aIt) |
| { |
| ::css::uno::Reference< ::css::lang::XComponent > xComponent( |
| aIt->getParagraph().get(), ::css::uno::UNO_QUERY); |
| if (xComponent.is()) |
| xComponent->dispose(); |
| } |
| } |
| |
| // static |
| ::css::uno::Any Document::mapFontColor(::Color const & rColor) |
| { |
| return ::css::uno::makeAny( |
| static_cast< ::sal_Int32 >(COLORDATA_RGB(rColor.GetColor()))); |
| // FIXME keep transparency? |
| } |
| |
| // static |
| ::Color Document::mapFontColor(::css::uno::Any const & rColor) |
| { |
| ::sal_Int32 nColor = 0; |
| rColor >>= nColor; |
| return ::Color(static_cast< ::ColorData >(nColor)); |
| } |
| |
| // static |
| ::css::uno::Any Document::mapFontWeight(::FontWeight nWeight) |
| { |
| // Map from ::FontWeight to ::css:awt::FontWeight, depends on order of |
| // elements in ::FontWeight (vcl/vclenum.hxx): |
| static float const aWeight[] |
| = { ::css::awt::FontWeight::DONTKNOW, // WEIGHT_DONTKNOW |
| ::css::awt::FontWeight::THIN, // WEIGHT_THIN |
| ::css::awt::FontWeight::ULTRALIGHT, // WEIGHT_ULTRALIGHT |
| ::css::awt::FontWeight::LIGHT, // WEIGHT_LIGHT |
| ::css::awt::FontWeight::SEMILIGHT, // WEIGHT_SEMILIGHT |
| ::css::awt::FontWeight::NORMAL, // WEIGHT_NORMAL |
| ::css::awt::FontWeight::NORMAL, // WEIGHT_MEDIUM |
| ::css::awt::FontWeight::SEMIBOLD, // WEIGHT_SEMIBOLD |
| ::css::awt::FontWeight::BOLD, // WEIGHT_BOLD |
| ::css::awt::FontWeight::ULTRABOLD, // WEIGHT_ULTRABOLD |
| ::css::awt::FontWeight::BLACK }; // WEIGHT_BLACK |
| return ::css::uno::makeAny(aWeight[nWeight]); |
| } |
| |
| // static |
| ::FontWeight Document::mapFontWeight(::css::uno::Any const & rWeight) |
| { |
| float nWeight = ::css::awt::FontWeight::NORMAL; |
| rWeight >>= nWeight; |
| return nWeight <= ::css::awt::FontWeight::DONTKNOW ? WEIGHT_DONTKNOW |
| : nWeight <= ::css::awt::FontWeight::THIN ? WEIGHT_THIN |
| : nWeight <= ::css::awt::FontWeight::ULTRALIGHT ? WEIGHT_ULTRALIGHT |
| : nWeight <= ::css::awt::FontWeight::LIGHT ? WEIGHT_LIGHT |
| : nWeight <= ::css::awt::FontWeight::SEMILIGHT ? WEIGHT_SEMILIGHT |
| : nWeight <= ::css::awt::FontWeight::NORMAL ? WEIGHT_NORMAL |
| : nWeight <= ::css::awt::FontWeight::SEMIBOLD ? WEIGHT_SEMIBOLD |
| : nWeight <= ::css::awt::FontWeight::BOLD ? WEIGHT_BOLD |
| : nWeight <= ::css::awt::FontWeight::ULTRABOLD ? WEIGHT_ULTRABOLD |
| : WEIGHT_BLACK; |
| } |
| |
| } |
| |