merge the formfield patch from ooo-build
[ooovba.git] / sw / source / core / doc / docruby.cxx
blob37d743c0d376f060dd03924b7a881b6420e4fc49
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() )
151 InsertPoolItem( aPam, pEntry->GetRubyAttr(), 0 );
153 else
155 ResetAttrs( aPam, TRUE, &aDelArr );
159 if( aCheckEntry.GetText() != pEntry->GetText() &&
160 pEntry->GetText().Len() )
162 // text is changed, so replace the original
163 ReplaceRange( aPam, pEntry->GetText(), false );
165 aPam.DeleteMark();
167 else
169 if( *aPam.GetPoint() < *pEnd )
171 // goto next paragraph
172 aPam.DeleteMark();
173 aPam.Move( fnMoveForward, fnGoNode );
175 else
177 const SwRubyListEntry* pEntry = rList[ nListEntry++ ];
179 // set/reset the attribut
180 if( pEntry->GetRubyAttr().GetText().Len() &&
181 pEntry->GetText().Len() )
183 InsertString( aPam, pEntry->GetText() );
184 aPam.SetMark();
185 aPam.GetMark()->nContent -= pEntry->GetText().Len();
186 InsertPoolItem( aPam, pEntry->GetRubyAttr(),
187 nsSetAttrMode::SETATTR_DONTEXPAND );
189 else
190 break;
191 aPam.DeleteMark();
194 } while( nListEntry < rList.Count() && *aPam.GetPoint() < *pEnd );
196 } while( 30 > rList.Count() &&
197 (_pStartCrsr=(SwPaM *)_pStartCrsr->GetNext()) != __pStartCrsr );
199 EndUndo( UNDO_SETRUBYATTR, NULL );
201 return nListEntry;
204 BOOL SwDoc::_SelectNextRubyChars( SwPaM& rPam, SwRubyListEntry& rEntry, USHORT )
206 // Point must be the startposition, Mark is optional the end position
207 SwPosition* pPos = rPam.GetPoint();
208 const SwTxtNode* pTNd = pPos->nNode.GetNode().GetTxtNode();
209 const String* pTxt = &pTNd->GetTxt();
210 xub_StrLen nStart = pPos->nContent.GetIndex(), nEnd = pTxt->Len();
212 BOOL bHasMark = rPam.HasMark();
213 if( bHasMark )
215 // in the same node?
216 if( rPam.GetMark()->nNode == pPos->nNode )
218 // then use that end
219 xub_StrLen nTEnd = rPam.GetMark()->nContent.GetIndex();
220 if( nTEnd < nEnd )
221 nEnd = nTEnd;
223 rPam.DeleteMark();
226 // ----- search the start
227 // --- look where a ruby attribut starts
228 USHORT nHtIdx = USHRT_MAX;
229 const SwpHints* pHts = pTNd->GetpSwpHints();
230 const SwTxtAttr* pAttr = 0;
231 if( pHts )
233 const SwTxtAttr* pHt;
234 for( nHtIdx = 0; nHtIdx < pHts->Count(); ++nHtIdx )
235 if( RES_TXTATR_CJK_RUBY == ( pHt = (*pHts)[ nHtIdx ])->Which() &&
236 *pHt->GetAnyEnd() > nStart )
238 if( *pHt->GetStart() < nEnd )
240 pAttr = pHt;
241 if( !bHasMark && nStart > *pAttr->GetStart() )
243 nStart = *pAttr->GetStart();
244 pPos->nContent = nStart;
247 break;
251 if( !bHasMark && nStart && ( !pAttr || nStart != *pAttr->GetStart()) )
253 // skip to the word begin!
254 long nWordStt = pBreakIt->GetBreakIter()->getWordBoundary(
255 *pTxt, nStart,
256 pBreakIt->GetLocale( pTNd->GetLang( nStart )),
257 WordType::ANYWORD_IGNOREWHITESPACES,
258 TRUE ).startPos;
259 if( nWordStt < nStart && -1 != nWordStt )
261 nStart = (xub_StrLen)nWordStt;
262 pPos->nContent = nStart;
266 BOOL bAlphaNum = FALSE;
267 long nWordEnd = nEnd;
268 CharClass& rCC = GetAppCharClass();
269 while( nStart < nEnd )
271 if( pAttr && nStart == *pAttr->GetStart() )
273 pPos->nContent = nStart;
274 if( !rPam.HasMark() )
276 rPam.SetMark();
277 pPos->nContent = *pAttr->GetAnyEnd();
278 if( pPos->nContent.GetIndex() > nEnd )
279 pPos->nContent = nEnd;
280 rEntry.SetRubyAttr( pAttr->GetRuby() );
282 break;
285 sal_Int32 nChType = rCC.getType( *pTxt, nStart );
286 BOOL bIgnoreChar = FALSE, bIsAlphaNum = FALSE, bChkNxtWrd = FALSE;
287 switch( nChType )
289 case UnicodeType::UPPERCASE_LETTER:
290 case UnicodeType::LOWERCASE_LETTER:
291 case UnicodeType::TITLECASE_LETTER:
292 case UnicodeType::DECIMAL_DIGIT_NUMBER:
293 bChkNxtWrd = bIsAlphaNum = TRUE;
294 break;
296 case UnicodeType::SPACE_SEPARATOR:
297 case UnicodeType::CONTROL:
298 /*??*/ case UnicodeType::PRIVATE_USE:
299 case UnicodeType::START_PUNCTUATION:
300 case UnicodeType::END_PUNCTUATION:
301 bIgnoreChar = TRUE;
302 break;
305 case UnicodeType::OTHER_LETTER:
306 bChkNxtWrd = TRUE;
307 // no break!
308 // case UnicodeType::UNASSIGNED:
309 // case UnicodeType::MODIFIER_LETTER:
310 // case UnicodeType::NON_SPACING_MARK:
311 // case UnicodeType::ENCLOSING_MARK:
312 // case UnicodeType::COMBINING_SPACING_MARK:
313 // case UnicodeType::LETTER_NUMBER:
314 // case UnicodeType::OTHER_NUMBER:
315 // case UnicodeType::LINE_SEPARATOR:
316 // case UnicodeType::PARAGRAPH_SEPARATOR:
317 // case UnicodeType::FORMAT:
318 // case UnicodeType::SURROGATE:
319 // case UnicodeType::DASH_PUNCTUATION:
320 // case UnicodeType::CONNECTOR_PUNCTUATION:
321 ///*?? */case UnicodeType::OTHER_PUNCTUATION:
322 //--> char '!' is to ignore!
323 // case UnicodeType::MATH_SYMBOL:
324 // case UnicodeType::CURRENCY_SYMBOL:
325 // case UnicodeType::MODIFIER_SYMBOL:
326 // case UnicodeType::OTHER_SYMBOL:
327 // case UnicodeType::INITIAL_PUNCTUATION:
328 // case UnicodeType::FINAL_PUNCTUATION:
329 default:
330 bIsAlphaNum = FALSE;
331 break;
334 if( rPam.HasMark() )
336 if( bIgnoreChar || bIsAlphaNum != bAlphaNum || nStart >= nWordEnd )
337 break;
339 else if( !bIgnoreChar )
341 rPam.SetMark();
342 bAlphaNum = bIsAlphaNum;
343 if( bChkNxtWrd && pBreakIt->GetBreakIter().is() )
345 // search the end of this word
346 nWordEnd = pBreakIt->GetBreakIter()->getWordBoundary(
347 *pTxt, nStart,
348 pBreakIt->GetLocale( pTNd->GetLang( nStart )),
349 WordType::ANYWORD_IGNOREWHITESPACES,
350 TRUE ).endPos;
351 if( 0 > nWordEnd || nWordEnd > nEnd || nWordEnd == nStart )
352 nWordEnd = nEnd;
355 pTNd->GoNext( &pPos->nContent, CRSR_SKIP_CHARS );
356 nStart = pPos->nContent.GetIndex();
359 nStart = rPam.GetMark()->nContent.GetIndex();
360 rEntry.SetText( pTxt->Copy( nStart,
361 rPam.GetPoint()->nContent.GetIndex() - nStart ));
362 return rPam.HasMark();
365 SwRubyListEntry::~SwRubyListEntry()