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