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