Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : :
30 : : #include <string.h> // for strchr()
31 : :
32 : : #include <com/sun/star/i18n/UnicodeType.hpp>
33 : : #include <com/sun/star/i18n/WordType.hpp>
34 : :
35 : : #include <unotools/charclass.hxx>
36 : :
37 : : #include <hintids.hxx>
38 : : #include <doc.hxx>
39 : : #include <IDocumentUndoRedo.hxx>
40 : : #include <docary.hxx>
41 : : #include <mvsave.hxx> // structures for Saving by Move/Delete
42 : : #include <ndtxt.hxx>
43 : : #include <txatbase.hxx>
44 : : #include <rubylist.hxx>
45 : : #include <pam.hxx>
46 : : #include <swundo.hxx> // for the UndoIds
47 : : #include <breakit.hxx>
48 : : #include <crsskip.hxx>
49 : :
50 : : using namespace ::com::sun::star::i18n;
51 : :
52 : :
53 : : /*
54 : : * Members in the list:
55 : : * - String - the orig text
56 : : * - SwFmtRuby - the ruby attribut
57 : : *
58 : : *
59 : : */
60 : 0 : sal_uInt16 SwDoc::FillRubyList( const SwPaM& rPam, SwRubyList& rList,
61 : : sal_uInt16 nMode )
62 : : {
63 : 0 : const SwPaM *_pStartCrsr = (SwPaM*)rPam.GetNext(),
64 : 0 : *__pStartCrsr = _pStartCrsr;
65 : 0 : sal_Bool bCheckEmpty = &rPam != _pStartCrsr;
66 [ # # ][ # # ]: 0 : do {
[ # # ]
67 : 0 : const SwPosition* pStt = _pStartCrsr->Start(),
68 : 0 : * pEnd = pStt == _pStartCrsr->GetPoint()
69 : : ? _pStartCrsr->GetMark()
70 [ # # ]: 0 : : _pStartCrsr->GetPoint();
71 [ # # ][ # # ]: 0 : if( !bCheckEmpty || ( pStt != pEnd && *pStt != *pEnd ))
[ # # ][ # # ]
72 : : {
73 [ # # ]: 0 : SwPaM aPam( *pStt );
74 [ # # ][ # # ]: 0 : do {
[ # # ]
75 [ # # ][ # # ]: 0 : SwRubyListEntry* pNew = new SwRubyListEntry;
76 [ # # ]: 0 : if( pEnd != pStt )
77 : : {
78 [ # # ]: 0 : aPam.SetMark();
79 [ # # ]: 0 : *aPam.GetMark() = *pEnd;
80 : : }
81 [ # # ][ # # ]: 0 : if( _SelectNextRubyChars( aPam, *pNew, nMode ))
82 : : {
83 [ # # ]: 0 : rList.push_back( pNew );
84 [ # # ]: 0 : aPam.DeleteMark();
85 : : }
86 : : else
87 : : {
88 [ # # ][ # # ]: 0 : delete pNew;
89 [ # # ][ # # ]: 0 : if( *aPam.GetPoint() < *pEnd )
90 : : {
91 : : // goto next paragraph
92 [ # # ]: 0 : aPam.DeleteMark();
93 [ # # ]: 0 : aPam.Move( fnMoveForward, fnGoNode );
94 : : }
95 : : else
96 : 0 : break;
97 : : }
98 [ # # ][ # # ]: 0 : } while( 30 > rList.size() && *aPam.GetPoint() < *pEnd );
99 : : }
100 : 0 : } while( 30 > rList.size() &&
101 : 0 : (_pStartCrsr=(SwPaM *)_pStartCrsr->GetNext()) != __pStartCrsr );
102 : :
103 : 0 : return rList.size();
104 : : }
105 : :
106 : 0 : sal_uInt16 SwDoc::SetRubyList( const SwPaM& rPam, const SwRubyList& rList,
107 : : sal_uInt16 nMode )
108 : : {
109 [ # # ][ # # ]: 0 : GetIDocumentUndoRedo().StartUndo( UNDO_SETRUBYATTR, NULL );
110 [ # # ]: 0 : std::set<sal_uInt16> aDelArr;
111 [ # # ]: 0 : aDelArr.insert( RES_TXTATR_CJK_RUBY );
112 : :
113 : 0 : sal_uInt16 nListEntry = 0;
114 : :
115 : 0 : const SwPaM *_pStartCrsr = (SwPaM*)rPam.GetNext(),
116 : 0 : *__pStartCrsr = _pStartCrsr;
117 : 0 : sal_Bool bCheckEmpty = &rPam != _pStartCrsr;
118 [ # # ][ # # ]: 0 : do {
[ # # ]
119 [ # # ]: 0 : const SwPosition* pStt = _pStartCrsr->Start(),
120 : 0 : * pEnd = pStt == _pStartCrsr->GetPoint()
121 : : ? _pStartCrsr->GetMark()
122 [ # # ]: 0 : : _pStartCrsr->GetPoint();
123 [ # # ][ # # ]: 0 : if( !bCheckEmpty || ( pStt != pEnd && *pStt != *pEnd ))
[ # # ][ # # ]
[ # # ]
124 : : {
125 : :
126 [ # # ]: 0 : SwPaM aPam( *pStt );
127 [ # # ][ # # ]: 0 : do {
[ # # ]
128 [ # # ]: 0 : SwRubyListEntry aCheckEntry;
129 [ # # ]: 0 : if( pEnd != pStt )
130 : : {
131 [ # # ]: 0 : aPam.SetMark();
132 [ # # ]: 0 : *aPam.GetMark() = *pEnd;
133 : : }
134 [ # # ][ # # ]: 0 : if( _SelectNextRubyChars( aPam, aCheckEntry, nMode ))
135 : : {
136 [ # # ]: 0 : const SwRubyListEntry* pEntry = &rList[ nListEntry++ ];
137 [ # # ][ # # ]: 0 : if( aCheckEntry.GetRubyAttr() != pEntry->GetRubyAttr() )
138 : : {
139 : : // set/reset the attribut
140 [ # # ]: 0 : if( pEntry->GetRubyAttr().GetText().Len() )
141 : : {
142 [ # # ]: 0 : InsertPoolItem( aPam, pEntry->GetRubyAttr(), 0 );
143 : : }
144 : : else
145 : : {
146 [ # # ]: 0 : ResetAttrs( aPam, sal_True, aDelArr );
147 : : }
148 : : }
149 : :
150 [ # # ]: 0 : if( aCheckEntry.GetText() != pEntry->GetText() &&
[ # # # # ]
[ # # ]
151 : 0 : pEntry->GetText().Len() )
152 : : {
153 : : // text is changed, so replace the original
154 [ # # ]: 0 : ReplaceRange( aPam, pEntry->GetText(), false );
155 : : }
156 [ # # ]: 0 : aPam.DeleteMark();
157 : : }
158 : : else
159 : : {
160 [ # # ][ # # ]: 0 : if( *aPam.GetPoint() < *pEnd )
161 : : {
162 : : // goto next paragraph
163 [ # # ]: 0 : aPam.DeleteMark();
164 [ # # ]: 0 : aPam.Move( fnMoveForward, fnGoNode );
165 : : }
166 : : else
167 : : {
168 [ # # ]: 0 : const SwRubyListEntry* pEntry = &rList[ nListEntry++ ];
169 : :
170 : : // set/reset the attribut
171 [ # # # # ]: 0 : if( pEntry->GetRubyAttr().GetText().Len() &&
[ # # ]
172 : 0 : pEntry->GetText().Len() )
173 : : {
174 [ # # ]: 0 : InsertString( aPam, pEntry->GetText() );
175 [ # # ]: 0 : aPam.SetMark();
176 [ # # ]: 0 : aPam.GetMark()->nContent -= pEntry->GetText().Len();
177 : 0 : InsertPoolItem( aPam, pEntry->GetRubyAttr(),
178 [ # # ]: 0 : nsSetAttrMode::SETATTR_DONTEXPAND );
179 : : }
180 : : else
181 : : break;
182 [ # # ]: 0 : aPam.DeleteMark();
183 : : }
184 [ # # ][ # # ]: 0 : }
185 [ # # ][ # # ]: 0 : } while( nListEntry < rList.size() && *aPam.GetPoint() < *pEnd );
186 : : }
187 : 0 : } while( 30 > rList.size() &&
188 : 0 : (_pStartCrsr=(SwPaM *)_pStartCrsr->GetNext()) != __pStartCrsr );
189 : :
190 [ # # ][ # # ]: 0 : GetIDocumentUndoRedo().EndUndo( UNDO_SETRUBYATTR, NULL );
191 : :
192 : 0 : return nListEntry;
193 : : }
194 : :
195 : 0 : sal_Bool SwDoc::_SelectNextRubyChars( SwPaM& rPam, SwRubyListEntry& rEntry, sal_uInt16 )
196 : : {
197 : : // Point must be the startposition, Mark is optional the end position
198 : 0 : SwPosition* pPos = rPam.GetPoint();
199 : 0 : const SwTxtNode* pTNd = pPos->nNode.GetNode().GetTxtNode();
200 : 0 : const String* pTxt = &pTNd->GetTxt();
201 : 0 : xub_StrLen nStart = pPos->nContent.GetIndex(), nEnd = pTxt->Len();
202 : :
203 : 0 : sal_Bool bHasMark = rPam.HasMark();
204 [ # # ]: 0 : if( bHasMark )
205 : : {
206 : : // in the same node?
207 [ # # ]: 0 : if( rPam.GetMark()->nNode == pPos->nNode )
208 : : {
209 : : // then use that end
210 : 0 : xub_StrLen nTEnd = rPam.GetMark()->nContent.GetIndex();
211 [ # # ]: 0 : if( nTEnd < nEnd )
212 : 0 : nEnd = nTEnd;
213 : : }
214 : 0 : rPam.DeleteMark();
215 : : }
216 : :
217 : : // ----- search the start
218 : : // --- look where a ruby attribut starts
219 : 0 : sal_uInt16 nHtIdx = USHRT_MAX;
220 : 0 : const SwpHints* pHts = pTNd->GetpSwpHints();
221 : 0 : const SwTxtAttr* pAttr = 0;
222 [ # # ]: 0 : if( pHts )
223 : : {
224 : : const SwTxtAttr* pHt;
225 [ # # ]: 0 : for( nHtIdx = 0; nHtIdx < pHts->Count(); ++nHtIdx )
226 [ # # # # ]: 0 : if( RES_TXTATR_CJK_RUBY == ( pHt = (*pHts)[ nHtIdx ])->Which() &&
[ # # ]
227 : 0 : *pHt->GetAnyEnd() > nStart )
228 : : {
229 [ # # ]: 0 : if( *pHt->GetStart() < nEnd )
230 : : {
231 : 0 : pAttr = pHt;
232 [ # # ][ # # ]: 0 : if( !bHasMark && nStart > *pAttr->GetStart() )
[ # # ]
233 : : {
234 : 0 : nStart = *pAttr->GetStart();
235 : 0 : pPos->nContent = nStart;
236 : : }
237 : : }
238 : 0 : break;
239 : : }
240 : : }
241 : :
242 [ # # ][ # # ]: 0 : if( !bHasMark && nStart && ( !pAttr || nStart != *pAttr->GetStart()) )
[ # # ][ # # ]
[ # # ]
243 : : {
244 : : // skip to the word begin!
245 [ # # ]: 0 : long nWordStt = pBreakIt->GetBreakIter()->getWordBoundary(
246 : : *pTxt, nStart,
247 [ # # ][ # # ]: 0 : pBreakIt->GetLocale( pTNd->GetLang( nStart )),
248 : : WordType::ANYWORD_IGNOREWHITESPACES,
249 [ # # ][ # # ]: 0 : sal_True ).startPos;
250 [ # # ][ # # ]: 0 : if( nWordStt < nStart && -1 != nWordStt )
251 : : {
252 : 0 : nStart = (xub_StrLen)nWordStt;
253 : 0 : pPos->nContent = nStart;
254 : : }
255 : : }
256 : :
257 : 0 : sal_Bool bAlphaNum = sal_False;
258 : 0 : long nWordEnd = nEnd;
259 : 0 : CharClass& rCC = GetAppCharClass();
260 [ # # ]: 0 : while( nStart < nEnd )
261 : : {
262 [ # # ][ # # ]: 0 : if( pAttr && nStart == *pAttr->GetStart() )
[ # # ]
263 : : {
264 : 0 : pPos->nContent = nStart;
265 [ # # ]: 0 : if( !rPam.HasMark() )
266 : : {
267 : 0 : rPam.SetMark();
268 : 0 : pPos->nContent = *pAttr->GetAnyEnd();
269 [ # # ]: 0 : if( pPos->nContent.GetIndex() > nEnd )
270 : 0 : pPos->nContent = nEnd;
271 : 0 : rEntry.SetRubyAttr( pAttr->GetRuby() );
272 : : }
273 : 0 : break;
274 : : }
275 : :
276 : 0 : sal_Int32 nChType = rCC.getType( *pTxt, nStart );
277 : 0 : sal_Bool bIgnoreChar = sal_False, bIsAlphaNum = sal_False, bChkNxtWrd = sal_False;
278 [ # # # # ]: 0 : switch( nChType )
279 : : {
280 : : case UnicodeType::UPPERCASE_LETTER:
281 : : case UnicodeType::LOWERCASE_LETTER:
282 : : case UnicodeType::TITLECASE_LETTER:
283 : : case UnicodeType::DECIMAL_DIGIT_NUMBER:
284 : 0 : bChkNxtWrd = bIsAlphaNum = sal_True;
285 : 0 : break;
286 : :
287 : : case UnicodeType::SPACE_SEPARATOR:
288 : : case UnicodeType::CONTROL:
289 : : /*??*/ case UnicodeType::PRIVATE_USE:
290 : : case UnicodeType::START_PUNCTUATION:
291 : : case UnicodeType::END_PUNCTUATION:
292 : 0 : bIgnoreChar = sal_True;
293 : 0 : break;
294 : :
295 : :
296 : : case UnicodeType::OTHER_LETTER:
297 : 0 : bChkNxtWrd = sal_True;
298 : :
299 : : default:
300 : 0 : bIsAlphaNum = sal_False;
301 : 0 : break;
302 : : }
303 : :
304 [ # # ]: 0 : if( rPam.HasMark() )
305 : : {
306 [ # # ][ # # ]: 0 : if( bIgnoreChar || bIsAlphaNum != bAlphaNum || nStart >= nWordEnd )
[ # # ]
307 : 0 : break;
308 : : }
309 [ # # ]: 0 : else if( !bIgnoreChar )
310 : : {
311 : 0 : rPam.SetMark();
312 : 0 : bAlphaNum = bIsAlphaNum;
313 [ # # ][ # # ]: 0 : if( bChkNxtWrd && pBreakIt->GetBreakIter().is() )
[ # # ]
[ # # # # ]
[ # # ]
314 : : {
315 : : // search the end of this word
316 [ # # ]: 0 : nWordEnd = pBreakIt->GetBreakIter()->getWordBoundary(
317 : : *pTxt, nStart,
318 [ # # ][ # # ]: 0 : pBreakIt->GetLocale( pTNd->GetLang( nStart )),
319 : : WordType::ANYWORD_IGNOREWHITESPACES,
320 [ # # ][ # # ]: 0 : sal_True ).endPos;
321 [ # # ][ # # ]: 0 : if( 0 > nWordEnd || nWordEnd > nEnd || nWordEnd == nStart )
[ # # ]
322 : 0 : nWordEnd = nEnd;
323 : : }
324 : : }
325 : 0 : pTNd->GoNext( &pPos->nContent, CRSR_SKIP_CHARS );
326 : 0 : nStart = pPos->nContent.GetIndex();
327 : : }
328 : :
329 : 0 : nStart = rPam.GetMark()->nContent.GetIndex();
330 : : rEntry.SetText( pTxt->Copy( nStart,
331 [ # # ]: 0 : rPam.GetPoint()->nContent.GetIndex() - nStart ));
332 : 0 : return rPam.HasMark();
333 : : }
334 : :
335 [ # # ]: 0 : SwRubyListEntry::~SwRubyListEntry()
336 : : {
337 : 0 : }
338 : :
339 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|