1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include "precompiled_sw.hxx"
29 
30 #include <textmarkuphelper.hxx>
31 #include <accportions.hxx>
32 
33 #include <vector>
34 #include <algorithm>
35 #include <comphelper/stlunosequence.hxx>
36 
37 #include <errhdl.hxx>
38 
39 #include <com/sun/star/text/TextMarkupType.hpp>
40 #include <com/sun/star/accessibility/TextSegment.hpp>
41 
42 #include <ndtxt.hxx>
43 #include <wrong.hxx>
44 
45 using namespace com::sun::star;
46 
47 // helper functions
48 namespace {
49     const SwWrongList* getTextMarkupList( const SwTxtNode& rTxtNode,
50                                           const sal_Int32 nTextMarkupType )
51         throw (::com::sun::star::lang::IllegalArgumentException,
52                ::com::sun::star::uno::RuntimeException)
53     {
54         const SwWrongList* pTextMarkupList( 0 );
55         switch ( nTextMarkupType )
56         {
57             case text::TextMarkupType::SPELLCHECK:
58             {
59                 pTextMarkupList = rTxtNode.GetWrong();
60             }
61             break;
62             case text::TextMarkupType::PROOFREADING:
63             {
64                 // support not implemented yet
65                 pTextMarkupList = 0;
66             }
67             break;
68             case text::TextMarkupType::SMARTTAG:
69             {
70                 // support not implemented yet
71                 pTextMarkupList = 0;
72             }
73             break;
74             default:
75             {
76                 throw lang::IllegalArgumentException();
77             }
78         }
79 
80         return pTextMarkupList;
81     }
82 }
83 
84 // implementation of class <SwTextMarkupoHelper>
85 SwTextMarkupHelper::SwTextMarkupHelper( const SwAccessiblePortionData& rPortionData,
86                                         const SwTxtNode& rTxtNode )
87     : mrPortionData( rPortionData )
88     // --> OD 2010-02-19 #i108125#
89     , mpTxtNode( &rTxtNode )
90     , mpTextMarkupList( 0 )
91     // <--
92 {
93 }
94 
95 // --> OD 2010-02-19 #i108125#
96 SwTextMarkupHelper::SwTextMarkupHelper( const SwAccessiblePortionData& rPortionData,
97                                         const SwWrongList& rTextMarkupList )
98     : mrPortionData( rPortionData )
99     , mpTxtNode( 0 )
100     , mpTextMarkupList( &rTextMarkupList )
101 {
102 }
103 // <--
104 
105 sal_Int32 SwTextMarkupHelper::getTextMarkupCount( const sal_Int32 nTextMarkupType )
106         throw (::com::sun::star::lang::IllegalArgumentException,
107                ::com::sun::star::uno::RuntimeException)
108 {
109     sal_Int32 nTextMarkupCount( 0 );
110 
111     // --> OD 2010-02-19 #i108125#
112     const SwWrongList* pTextMarkupList =
113                             mpTextMarkupList
114                             ? mpTextMarkupList
115                             : getTextMarkupList( *mpTxtNode, nTextMarkupType );
116     // <--
117     if ( pTextMarkupList )
118     {
119         nTextMarkupCount = pTextMarkupList->Count();
120     }
121 
122     return nTextMarkupCount;
123 }
124 ::com::sun::star::accessibility::TextSegment
125         SwTextMarkupHelper::getTextMarkup( const sal_Int32 nTextMarkupIndex,
126                                            const sal_Int32 nTextMarkupType )
127         throw (::com::sun::star::lang::IndexOutOfBoundsException,
128                ::com::sun::star::lang::IllegalArgumentException,
129                ::com::sun::star::uno::RuntimeException)
130 {
131     if ( nTextMarkupIndex >= getTextMarkupCount( nTextMarkupType ) ||
132          nTextMarkupIndex < 0 )
133     {
134         throw lang::IndexOutOfBoundsException();
135     }
136 
137     ::com::sun::star::accessibility::TextSegment aTextMarkupSegment;
138     aTextMarkupSegment.SegmentStart = -1;
139     aTextMarkupSegment.SegmentEnd = -1;
140 
141     // --> OD 2010-02-19 #i108125#
142     const SwWrongList* pTextMarkupList =
143                             mpTextMarkupList
144                             ? mpTextMarkupList
145                             : getTextMarkupList( *mpTxtNode, nTextMarkupType );
146     // <--
147     if ( pTextMarkupList )
148     {
149         const SwWrongArea* pTextMarkup =
150                 pTextMarkupList->GetElement( static_cast<sal_uInt16>(nTextMarkupIndex) );
151         if ( pTextMarkup )
152         {
153             const ::rtl::OUString rText = mrPortionData.GetAccessibleString();
154             const sal_Int32 nStartPos =
155                             mrPortionData.GetAccessiblePosition( pTextMarkup->mnPos );
156             const sal_Int32 nEndPos =
157                             mrPortionData.GetAccessiblePosition( pTextMarkup->mnPos + pTextMarkup->mnLen );
158             aTextMarkupSegment.SegmentText = rText.copy( nStartPos, nEndPos - nStartPos );
159             aTextMarkupSegment.SegmentStart = nStartPos;
160             aTextMarkupSegment.SegmentEnd = nEndPos;
161         }
162         else
163         {
164             ASSERT( false,
165                     "<SwTextMarkupHelper::getTextMarkup(..)> - missing <SwWrongArea> instance" );
166         }
167     }
168 
169     return aTextMarkupSegment;
170 }
171 
172 ::com::sun::star::uno::Sequence< ::com::sun::star::accessibility::TextSegment >
173         SwTextMarkupHelper::getTextMarkupAtIndex( const sal_Int32 nCharIndex,
174                                                   const sal_Int32 nTextMarkupType )
175         throw (::com::sun::star::lang::IndexOutOfBoundsException,
176                ::com::sun::star::lang::IllegalArgumentException,
177                ::com::sun::star::uno::RuntimeException)
178 {
179     // assumption:
180     // value of <nCharIndex> is in range [0..length of accessible text)
181 
182     const sal_uInt16 nCoreCharIndex = mrPortionData.GetModelPosition( nCharIndex );
183     // Handling of portions with core length == 0 at the beginning of the
184     // paragraph - e.g. numbering portion.
185     if ( mrPortionData.GetAccessiblePosition( nCoreCharIndex ) > nCharIndex )
186     {
187         return uno::Sequence< ::com::sun::star::accessibility::TextSegment >();
188     }
189 
190     // --> OD 2010-02-19 #i108125#
191     const SwWrongList* pTextMarkupList =
192                             mpTextMarkupList
193                             ? mpTextMarkupList
194                             : getTextMarkupList( *mpTxtNode, nTextMarkupType );
195     // <--
196     ::std::vector< ::com::sun::star::accessibility::TextSegment > aTmpTextMarkups;
197     if ( pTextMarkupList )
198     {
199         const ::rtl::OUString rText = mrPortionData.GetAccessibleString();
200 
201         const sal_uInt16 nTextMarkupCount = pTextMarkupList->Count();
202         for ( sal_uInt16 nTextMarkupIdx = 0; nTextMarkupIdx < nTextMarkupCount; ++nTextMarkupIdx )
203         {
204             const SwWrongArea* pTextMarkup =
205                     pTextMarkupList->GetElement( static_cast<sal_uInt16>(nTextMarkupIdx) );
206             ASSERT( pTextMarkup,
207                     "<SwTextMarkupHelper::getTextMarkup(..)> - missing <SwWrongArea> instance" );
208             if ( pTextMarkup &&
209                  pTextMarkup->mnPos <= nCoreCharIndex &&
210                  nCoreCharIndex < ( pTextMarkup->mnPos + pTextMarkup->mnLen ) )
211             {
212                 const sal_Int32 nStartPos =
213                     mrPortionData.GetAccessiblePosition( pTextMarkup->mnPos );
214                 const sal_Int32 nEndPos =
215                     mrPortionData.GetAccessiblePosition( pTextMarkup->mnPos + pTextMarkup->mnLen );
216                 ::com::sun::star::accessibility::TextSegment aTextMarkupSegment;
217                 aTextMarkupSegment.SegmentText = rText.copy( nStartPos, nEndPos - nStartPos );
218                 aTextMarkupSegment.SegmentStart = nStartPos;
219                 aTextMarkupSegment.SegmentEnd = nEndPos;
220                 aTmpTextMarkups.push_back( aTextMarkupSegment );
221             }
222         }
223     }
224 
225     uno::Sequence< ::com::sun::star::accessibility::TextSegment > aTextMarkups(
226                                                     aTmpTextMarkups.size() );
227     ::std::copy( aTmpTextMarkups.begin(), aTmpTextMarkups.end(),
228                  ::comphelper::stl_begin( aTextMarkups ) );
229 
230     return aTextMarkups;
231 }
232