update dev300-m58
[ooovba.git] / sw / source / core / doc / docruby.cxx
blob8f93ef415ac8aebade5b20737dca75619aebd4c9
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: docruby.cxx,v $
10 * $Revision: 1.13 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
35 #include <string.h> // fuer strchr()
36 #include <hintids.hxx>
38 #ifndef _COM_SUN_STAR_I18N_UNICODETYPE_HDL
39 #include <com/sun/star/i18n/UnicodeType.hdl>
40 #endif
41 #ifndef _COM_SUN_STAR_I18N_WORDTYPE_HDL
42 #include <com/sun/star/i18n/WordType.hdl>
43 #endif
44 #include <unotools/charclass.hxx>
45 #include <doc.hxx>
46 #include <docary.hxx>
47 #include <mvsave.hxx> // Strukturen zum Sichern beim Move/Delete
48 #include <ndtxt.hxx>
49 #include <txatbase.hxx>
50 #include <rubylist.hxx>
51 #include <pam.hxx>
52 #include <swundo.hxx> // fuer die UndoIds
53 #include <undobj.hxx>
54 #include <breakit.hxx>
55 #include <crsskip.hxx>
57 SV_IMPL_PTRARR( SwRubyList, SwRubyListEntryPtr )
59 using namespace ::com::sun::star::i18n;
63 * Members in the list:
64 * - String - the orig text
65 * - SwFmtRuby - the ruby attribut
69 USHORT SwDoc::FillRubyList( const SwPaM& rPam, SwRubyList& rList,
70 USHORT nMode )
72 const SwPaM *_pStartCrsr = (SwPaM*)rPam.GetNext(),
73 *__pStartCrsr = _pStartCrsr;
74 BOOL bCheckEmpty = &rPam != _pStartCrsr;
75 do {
76 const SwPosition* pStt = _pStartCrsr->Start(),
77 * pEnd = pStt == _pStartCrsr->GetPoint()
78 ? _pStartCrsr->GetMark()
79 : _pStartCrsr->GetPoint();
80 if( !bCheckEmpty || ( pStt != pEnd && *pStt != *pEnd ))
82 SwPaM aPam( *pStt );
83 do {
84 SwRubyListEntry* pNew = new SwRubyListEntry;
85 if( pEnd != pStt )
87 aPam.SetMark();
88 *aPam.GetMark() = *pEnd;
90 if( _SelectNextRubyChars( aPam, *pNew, nMode ))
92 rList.Insert( pNew, rList.Count() );
93 aPam.DeleteMark();
95 else
97 delete pNew;
98 if( *aPam.GetPoint() < *pEnd )
100 // goto next paragraph
101 aPam.DeleteMark();
102 aPam.Move( fnMoveForward, fnGoNode );
104 else
105 break;
107 } while( 30 > rList.Count() && *aPam.GetPoint() < *pEnd );
109 } while( 30 > rList.Count() &&
110 (_pStartCrsr=(SwPaM *)_pStartCrsr->GetNext()) != __pStartCrsr );
112 return rList.Count();
115 USHORT SwDoc::SetRubyList( const SwPaM& rPam, const SwRubyList& rList,
116 USHORT nMode )
118 StartUndo( UNDO_SETRUBYATTR, NULL );
119 SvUShortsSort aDelArr;
120 aDelArr.Insert( RES_TXTATR_CJK_RUBY );
122 USHORT nListEntry = 0;
124 const SwPaM *_pStartCrsr = (SwPaM*)rPam.GetNext(),
125 *__pStartCrsr = _pStartCrsr;
126 BOOL bCheckEmpty = &rPam != _pStartCrsr;
127 do {
128 const SwPosition* pStt = _pStartCrsr->Start(),
129 * pEnd = pStt == _pStartCrsr->GetPoint()
130 ? _pStartCrsr->GetMark()
131 : _pStartCrsr->GetPoint();
132 if( !bCheckEmpty || ( pStt != pEnd && *pStt != *pEnd ))
135 SwPaM aPam( *pStt );
136 do {
137 SwRubyListEntry aCheckEntry;
138 if( pEnd != pStt )
140 aPam.SetMark();
141 *aPam.GetMark() = *pEnd;
143 if( _SelectNextRubyChars( aPam, aCheckEntry, nMode ))
145 const SwRubyListEntry* pEntry = rList[ nListEntry++ ];
146 if( aCheckEntry.GetRubyAttr() != pEntry->GetRubyAttr() )
148 // set/reset the attribut
149 if( pEntry->GetRubyAttr().GetText().Len() )
150 Insert( aPam, pEntry->GetRubyAttr(), 0 );
151 else
152 ResetAttrs( aPam, TRUE, &aDelArr );
155 if( aCheckEntry.GetText() != pEntry->GetText() &&
156 pEntry->GetText().Len() )
158 // text is changed, so replace the original
159 Replace( aPam, pEntry->GetText(), FALSE );
161 aPam.DeleteMark();
163 else
165 if( *aPam.GetPoint() < *pEnd )
167 // goto next paragraph
168 aPam.DeleteMark();
169 aPam.Move( fnMoveForward, fnGoNode );
171 else
173 const SwRubyListEntry* pEntry = rList[ nListEntry++ ];
175 // set/reset the attribut
176 if( pEntry->GetRubyAttr().GetText().Len() &&
177 pEntry->GetText().Len() )
179 Insert( aPam, pEntry->GetText(), true );
180 aPam.SetMark();
181 aPam.GetMark()->nContent -= pEntry->GetText().Len();
182 Insert( aPam, pEntry->GetRubyAttr(), nsSetAttrMode::SETATTR_DONTEXPAND );
184 else
185 break;
186 aPam.DeleteMark();
189 } while( nListEntry < rList.Count() && *aPam.GetPoint() < *pEnd );
191 } while( 30 > rList.Count() &&
192 (_pStartCrsr=(SwPaM *)_pStartCrsr->GetNext()) != __pStartCrsr );
194 EndUndo( UNDO_SETRUBYATTR, NULL );
196 return nListEntry;
199 BOOL SwDoc::_SelectNextRubyChars( SwPaM& rPam, SwRubyListEntry& rEntry, USHORT )
201 // Point must be the startposition, Mark is optional the end position
202 SwPosition* pPos = rPam.GetPoint();
203 const SwTxtNode* pTNd = pPos->nNode.GetNode().GetTxtNode();
204 const String* pTxt = &pTNd->GetTxt();
205 xub_StrLen nStart = pPos->nContent.GetIndex(), nEnd = pTxt->Len();
207 BOOL bHasMark = rPam.HasMark();
208 if( bHasMark )
210 // in the same node?
211 if( rPam.GetMark()->nNode == pPos->nNode )
213 // then use that end
214 xub_StrLen nTEnd = rPam.GetMark()->nContent.GetIndex();
215 if( nTEnd < nEnd )
216 nEnd = nTEnd;
218 rPam.DeleteMark();
221 // ----- search the start
222 // --- look where a ruby attribut starts
223 USHORT nHtIdx = USHRT_MAX;
224 const SwpHints* pHts = pTNd->GetpSwpHints();
225 const SwTxtAttr* pAttr = 0;
226 if( pHts )
228 const SwTxtAttr* pHt;
229 for( nHtIdx = 0; nHtIdx < pHts->Count(); ++nHtIdx )
230 if( RES_TXTATR_CJK_RUBY == ( pHt = (*pHts)[ nHtIdx ])->Which() &&
231 *pHt->GetAnyEnd() > nStart )
233 if( *pHt->GetStart() < nEnd )
235 pAttr = pHt;
236 if( !bHasMark && nStart > *pAttr->GetStart() )
238 nStart = *pAttr->GetStart();
239 pPos->nContent = nStart;
242 break;
246 if( !bHasMark && nStart && ( !pAttr || nStart != *pAttr->GetStart()) )
248 // skip to the word begin!
249 long nWordStt = pBreakIt->GetBreakIter()->getWordBoundary(
250 *pTxt, nStart,
251 pBreakIt->GetLocale( pTNd->GetLang( nStart )),
252 WordType::ANYWORD_IGNOREWHITESPACES,
253 TRUE ).startPos;
254 if( nWordStt < nStart && -1 != nWordStt )
256 nStart = (xub_StrLen)nWordStt;
257 pPos->nContent = nStart;
261 BOOL bAlphaNum = FALSE;
262 long nWordEnd = nEnd;
263 CharClass& rCC = GetAppCharClass();
264 while( nStart < nEnd )
266 if( pAttr && nStart == *pAttr->GetStart() )
268 pPos->nContent = nStart;
269 if( !rPam.HasMark() )
271 rPam.SetMark();
272 pPos->nContent = *pAttr->GetAnyEnd();
273 if( pPos->nContent.GetIndex() > nEnd )
274 pPos->nContent = nEnd;
275 rEntry.SetRubyAttr( pAttr->GetRuby() );
277 break;
280 sal_Int32 nChType = rCC.getType( *pTxt, nStart );
281 BOOL bIgnoreChar = FALSE, bIsAlphaNum = FALSE, bChkNxtWrd = FALSE;
282 switch( nChType )
284 case UnicodeType::UPPERCASE_LETTER:
285 case UnicodeType::LOWERCASE_LETTER:
286 case UnicodeType::TITLECASE_LETTER:
287 case UnicodeType::DECIMAL_DIGIT_NUMBER:
288 bChkNxtWrd = bIsAlphaNum = TRUE;
289 break;
291 case UnicodeType::SPACE_SEPARATOR:
292 case UnicodeType::CONTROL:
293 /*??*/ case UnicodeType::PRIVATE_USE:
294 case UnicodeType::START_PUNCTUATION:
295 case UnicodeType::END_PUNCTUATION:
296 bIgnoreChar = TRUE;
297 break;
300 case UnicodeType::OTHER_LETTER:
301 bChkNxtWrd = TRUE;
302 // no break!
303 // case UnicodeType::UNASSIGNED:
304 // case UnicodeType::MODIFIER_LETTER:
305 // case UnicodeType::NON_SPACING_MARK:
306 // case UnicodeType::ENCLOSING_MARK:
307 // case UnicodeType::COMBINING_SPACING_MARK:
308 // case UnicodeType::LETTER_NUMBER:
309 // case UnicodeType::OTHER_NUMBER:
310 // case UnicodeType::LINE_SEPARATOR:
311 // case UnicodeType::PARAGRAPH_SEPARATOR:
312 // case UnicodeType::FORMAT:
313 // case UnicodeType::SURROGATE:
314 // case UnicodeType::DASH_PUNCTUATION:
315 // case UnicodeType::CONNECTOR_PUNCTUATION:
316 ///*?? */case UnicodeType::OTHER_PUNCTUATION:
317 //--> char '!' is to ignore!
318 // case UnicodeType::MATH_SYMBOL:
319 // case UnicodeType::CURRENCY_SYMBOL:
320 // case UnicodeType::MODIFIER_SYMBOL:
321 // case UnicodeType::OTHER_SYMBOL:
322 // case UnicodeType::INITIAL_PUNCTUATION:
323 // case UnicodeType::FINAL_PUNCTUATION:
324 default:
325 bIsAlphaNum = FALSE;
326 break;
329 if( rPam.HasMark() )
331 if( bIgnoreChar || bIsAlphaNum != bAlphaNum || nStart >= nWordEnd )
332 break;
334 else if( !bIgnoreChar )
336 rPam.SetMark();
337 bAlphaNum = bIsAlphaNum;
338 if( bChkNxtWrd && pBreakIt->GetBreakIter().is() )
340 // search the end of this word
341 nWordEnd = pBreakIt->GetBreakIter()->getWordBoundary(
342 *pTxt, nStart,
343 pBreakIt->GetLocale( pTNd->GetLang( nStart )),
344 WordType::ANYWORD_IGNOREWHITESPACES,
345 TRUE ).endPos;
346 if( 0 > nWordEnd || nWordEnd > nEnd || nWordEnd == nStart )
347 nWordEnd = nEnd;
350 pTNd->GoNext( &pPos->nContent, CRSR_SKIP_CHARS );
351 nStart = pPos->nContent.GetIndex();
354 nStart = rPam.GetMark()->nContent.GetIndex();
355 rEntry.SetText( pTxt->Copy( nStart,
356 rPam.GetPoint()->nContent.GetIndex() - nStart ));
357 return rPam.HasMark();
360 SwRubyListEntry::~SwRubyListEntry()