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