1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26
27 #include <string.h> // fuer strchr()
28
29 #include <com/sun/star/i18n/UnicodeType.hdl>
30 #include <com/sun/star/i18n/WordType.hdl>
31
32 #include <unotools/charclass.hxx>
33
34 #include <hintids.hxx>
35 #include <doc.hxx>
36 #include <IDocumentUndoRedo.hxx>
37 #include <docary.hxx>
38 #include <mvsave.hxx> // Strukturen zum Sichern beim Move/Delete
39 #include <ndtxt.hxx>
40 #include <txatbase.hxx>
41 #include <rubylist.hxx>
42 #include <pam.hxx>
43 #include <swundo.hxx> // fuer die UndoIds
44 #include <breakit.hxx>
45 #include <crsskip.hxx>
46
47 SV_IMPL_PTRARR( SwRubyList, SwRubyListEntryPtr )
48
49 using namespace ::com::sun::star::i18n;
50
51
52 /*
53 * Members in the list:
54 * - String - the orig text
55 * - SwFmtRuby - the ruby attribut
56 *
57 *
58 */
FillRubyList(const SwPaM & rPam,SwRubyList & rList,sal_uInt16 nMode)59 sal_uInt16 SwDoc::FillRubyList( const SwPaM& rPam, SwRubyList& rList,
60 sal_uInt16 nMode )
61 {
62 const SwPaM *_pStartCrsr = (SwPaM*)rPam.GetNext(),
63 *__pStartCrsr = _pStartCrsr;
64 sal_Bool bCheckEmpty = &rPam != _pStartCrsr;
65 do {
66 const SwPosition* pStt = _pStartCrsr->Start(),
67 * pEnd = pStt == _pStartCrsr->GetPoint()
68 ? _pStartCrsr->GetMark()
69 : _pStartCrsr->GetPoint();
70 if( !bCheckEmpty || ( pStt != pEnd && *pStt != *pEnd ))
71 {
72 SwPaM aPam( *pStt );
73 do {
74 SwRubyListEntry* pNew = new SwRubyListEntry;
75 if( pEnd != pStt )
76 {
77 aPam.SetMark();
78 *aPam.GetMark() = *pEnd;
79 }
80 if( _SelectNextRubyChars( aPam, *pNew, nMode ))
81 {
82 rList.Insert( pNew, rList.Count() );
83 aPam.DeleteMark();
84 }
85 else
86 {
87 delete pNew;
88 if( *aPam.GetPoint() < *pEnd )
89 {
90 // goto next paragraph
91 aPam.DeleteMark();
92 aPam.Move( fnMoveForward, fnGoNode );
93 }
94 else
95 break;
96 }
97 } while( 30 > rList.Count() && *aPam.GetPoint() < *pEnd );
98 }
99 } while( 30 > rList.Count() &&
100 (_pStartCrsr=(SwPaM *)_pStartCrsr->GetNext()) != __pStartCrsr );
101
102 return rList.Count();
103 }
104
SetRubyList(const SwPaM & rPam,const SwRubyList & rList,sal_uInt16 nMode)105 sal_uInt16 SwDoc::SetRubyList( const SwPaM& rPam, const SwRubyList& rList,
106 sal_uInt16 nMode )
107 {
108 GetIDocumentUndoRedo().StartUndo( UNDO_SETRUBYATTR, NULL );
109 SvUShortsSort aDelArr;
110 aDelArr.Insert( RES_TXTATR_CJK_RUBY );
111
112 sal_uInt16 nListEntry = 0;
113
114 const SwPaM *_pStartCrsr = (SwPaM*)rPam.GetNext(),
115 *__pStartCrsr = _pStartCrsr;
116 sal_Bool bCheckEmpty = &rPam != _pStartCrsr;
117 do {
118 const SwPosition* pStt = _pStartCrsr->Start(),
119 * pEnd = pStt == _pStartCrsr->GetPoint()
120 ? _pStartCrsr->GetMark()
121 : _pStartCrsr->GetPoint();
122 if( !bCheckEmpty || ( pStt != pEnd && *pStt != *pEnd ))
123 {
124
125 SwPaM aPam( *pStt );
126 do {
127 SwRubyListEntry aCheckEntry;
128 if( pEnd != pStt )
129 {
130 aPam.SetMark();
131 *aPam.GetMark() = *pEnd;
132 }
133 if( _SelectNextRubyChars( aPam, aCheckEntry, nMode ))
134 {
135 const SwRubyListEntry* pEntry = rList[ nListEntry++ ];
136 if( aCheckEntry.GetRubyAttr() != pEntry->GetRubyAttr() )
137 {
138 // set/reset the attribut
139 if( pEntry->GetRubyAttr().GetText().Len() )
140 {
141 InsertPoolItem( aPam, pEntry->GetRubyAttr(), 0 );
142 }
143 else
144 {
145 ResetAttrs( aPam, sal_True, &aDelArr );
146 }
147 }
148
149 if( aCheckEntry.GetText() != pEntry->GetText() &&
150 pEntry->GetText().Len() )
151 {
152 // text is changed, so replace the original
153 ReplaceRange( aPam, pEntry->GetText(), false );
154 }
155 aPam.DeleteMark();
156 }
157 else
158 {
159 if( *aPam.GetPoint() < *pEnd )
160 {
161 // goto next paragraph
162 aPam.DeleteMark();
163 aPam.Move( fnMoveForward, fnGoNode );
164 }
165 else
166 {
167 const SwRubyListEntry* pEntry = rList[ nListEntry++ ];
168
169 // set/reset the attribut
170 if( pEntry->GetRubyAttr().GetText().Len() &&
171 pEntry->GetText().Len() )
172 {
173 InsertString( aPam, pEntry->GetText() );
174 aPam.SetMark();
175 aPam.GetMark()->nContent -= pEntry->GetText().Len();
176 InsertPoolItem(
177 aPam, pEntry->GetRubyAttr(), nsSetAttrMode::SETATTR_DONTEXPAND );
178 }
179 else
180 break;
181 aPam.DeleteMark();
182 }
183 }
184 } while( nListEntry < rList.Count() && *aPam.GetPoint() < *pEnd );
185 }
186 } while( 30 > rList.Count() &&
187 (_pStartCrsr=(SwPaM *)_pStartCrsr->GetNext()) != __pStartCrsr );
188
189 GetIDocumentUndoRedo().EndUndo( UNDO_SETRUBYATTR, NULL );
190
191 return nListEntry;
192 }
193
_SelectNextRubyChars(SwPaM & rPam,SwRubyListEntry & rEntry,sal_uInt16)194 sal_Bool SwDoc::_SelectNextRubyChars( SwPaM& rPam, SwRubyListEntry& rEntry, sal_uInt16 )
195 {
196 // Point must be the startposition, Mark is optional the end position
197 SwPosition* pPos = rPam.GetPoint();
198 const SwTxtNode* pTNd = pPos->nNode.GetNode().GetTxtNode();
199 const String* pTxt = &pTNd->GetTxt();
200 xub_StrLen nStart = pPos->nContent.GetIndex(), nEnd = pTxt->Len();
201
202 sal_Bool bHasMark = rPam.HasMark();
203 if( bHasMark )
204 {
205 // in the same node?
206 if( rPam.GetMark()->nNode == pPos->nNode )
207 {
208 // then use that end
209 xub_StrLen nTEnd = rPam.GetMark()->nContent.GetIndex();
210 if( nTEnd < nEnd )
211 nEnd = nTEnd;
212 }
213 rPam.DeleteMark();
214 }
215
216 // ----- search the start
217 // --- look where a ruby attribut starts
218 sal_uInt16 nHtIdx = USHRT_MAX;
219 const SwpHints* pHts = pTNd->GetpSwpHints();
220 const SwTxtAttr* pAttr = 0;
221 if( pHts )
222 {
223 const SwTxtAttr* pHt;
224 for( nHtIdx = 0; nHtIdx < pHts->Count(); ++nHtIdx )
225 if( RES_TXTATR_CJK_RUBY == ( pHt = (*pHts)[ nHtIdx ])->Which() &&
226 *pHt->GetAnyEnd() > nStart )
227 {
228 if( *pHt->GetStart() < nEnd )
229 {
230 pAttr = pHt;
231 if( !bHasMark && nStart > *pAttr->GetStart() )
232 {
233 nStart = *pAttr->GetStart();
234 pPos->nContent = nStart;
235 }
236 }
237 break;
238 }
239 }
240
241 if( !bHasMark && nStart && ( !pAttr || nStart != *pAttr->GetStart()) )
242 {
243 // skip to the word begin!
244 long nWordStt = pBreakIt->GetBreakIter()->getWordBoundary(
245 *pTxt, nStart,
246 pBreakIt->GetLocale( pTNd->GetLang( nStart )),
247 WordType::ANYWORD_IGNOREWHITESPACES,
248 sal_True ).startPos;
249 if( nWordStt < nStart && -1 != nWordStt )
250 {
251 nStart = (xub_StrLen)nWordStt;
252 pPos->nContent = nStart;
253 }
254 }
255
256 sal_Bool bAlphaNum = sal_False;
257 long nWordEnd = nEnd;
258 CharClass& rCC = GetAppCharClass();
259 while( nStart < nEnd )
260 {
261 if( pAttr && nStart == *pAttr->GetStart() )
262 {
263 pPos->nContent = nStart;
264 if( !rPam.HasMark() )
265 {
266 rPam.SetMark();
267 pPos->nContent = *pAttr->GetAnyEnd();
268 if( pPos->nContent.GetIndex() > nEnd )
269 pPos->nContent = nEnd;
270 rEntry.SetRubyAttr( pAttr->GetRuby() );
271 }
272 break;
273 }
274
275 sal_Int32 nChType = rCC.getType( *pTxt, nStart );
276 sal_Bool bIgnoreChar = sal_False, bIsAlphaNum = sal_False, bChkNxtWrd = sal_False;
277 switch( nChType )
278 {
279 case UnicodeType::UPPERCASE_LETTER:
280 case UnicodeType::LOWERCASE_LETTER:
281 case UnicodeType::TITLECASE_LETTER:
282 case UnicodeType::DECIMAL_DIGIT_NUMBER:
283 bChkNxtWrd = bIsAlphaNum = sal_True;
284 break;
285
286 case UnicodeType::SPACE_SEPARATOR:
287 case UnicodeType::CONTROL:
288 /*??*/ case UnicodeType::PRIVATE_USE:
289 case UnicodeType::START_PUNCTUATION:
290 case UnicodeType::END_PUNCTUATION:
291 bIgnoreChar = sal_True;
292 break;
293
294
295 case UnicodeType::OTHER_LETTER:
296 bChkNxtWrd = sal_True;
297 // no break!
298 // case UnicodeType::UNASSIGNED:
299 // case UnicodeType::MODIFIER_LETTER:
300 // case UnicodeType::NON_SPACING_MARK:
301 // case UnicodeType::ENCLOSING_MARK:
302 // case UnicodeType::COMBINING_SPACING_MARK:
303 // case UnicodeType::LETTER_NUMBER:
304 // case UnicodeType::OTHER_NUMBER:
305 // case UnicodeType::LINE_SEPARATOR:
306 // case UnicodeType::PARAGRAPH_SEPARATOR:
307 // case UnicodeType::FORMAT:
308 // case UnicodeType::SURROGATE:
309 // case UnicodeType::DASH_PUNCTUATION:
310 // case UnicodeType::CONNECTOR_PUNCTUATION:
311 ///*?? */case UnicodeType::OTHER_PUNCTUATION:
312 //--> char '!' is to ignore!
313 // case UnicodeType::MATH_SYMBOL:
314 // case UnicodeType::CURRENCY_SYMBOL:
315 // case UnicodeType::MODIFIER_SYMBOL:
316 // case UnicodeType::OTHER_SYMBOL:
317 // case UnicodeType::INITIAL_PUNCTUATION:
318 // case UnicodeType::FINAL_PUNCTUATION:
319 default:
320 bIsAlphaNum = sal_False;
321 break;
322 }
323
324 if( rPam.HasMark() )
325 {
326 if( bIgnoreChar || bIsAlphaNum != bAlphaNum || nStart >= nWordEnd )
327 break;
328 }
329 else if( !bIgnoreChar )
330 {
331 rPam.SetMark();
332 bAlphaNum = bIsAlphaNum;
333 if( bChkNxtWrd && pBreakIt->GetBreakIter().is() )
334 {
335 // search the end of this word
336 nWordEnd = pBreakIt->GetBreakIter()->getWordBoundary(
337 *pTxt, nStart,
338 pBreakIt->GetLocale( pTNd->GetLang( nStart )),
339 WordType::ANYWORD_IGNOREWHITESPACES,
340 sal_True ).endPos;
341 if( 0 > nWordEnd || nWordEnd > nEnd || nWordEnd == nStart )
342 nWordEnd = nEnd;
343 }
344 }
345 pTNd->GoNext( &pPos->nContent, CRSR_SKIP_CHARS );
346 nStart = pPos->nContent.GetIndex();
347 }
348
349 nStart = rPam.GetMark()->nContent.GetIndex();
350 rEntry.SetText( pTxt->Copy( nStart,
351 rPam.GetPoint()->nContent.GetIndex() - nStart ));
352 return rPam.HasMark();
353 }
354
~SwRubyListEntry()355 SwRubyListEntry::~SwRubyListEntry()
356 {
357 }
358