1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: docruby.cxx,v $
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>
41 #ifndef _COM_SUN_STAR_I18N_WORDTYPE_HDL
42 #include <com/sun/star/i18n/WordType.hdl>
44 #include <unotools/charclass.hxx>
47 #include <mvsave.hxx> // Strukturen zum Sichern beim Move/Delete
49 #include <txatbase.hxx>
50 #include <rubylist.hxx>
52 #include <swundo.hxx> // fuer die UndoIds
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
,
72 const SwPaM
*_pStartCrsr
= (SwPaM
*)rPam
.GetNext(),
73 *__pStartCrsr
= _pStartCrsr
;
74 BOOL bCheckEmpty
= &rPam
!= _pStartCrsr
;
76 const SwPosition
* pStt
= _pStartCrsr
->Start(),
77 * pEnd
= pStt
== _pStartCrsr
->GetPoint()
78 ? _pStartCrsr
->GetMark()
79 : _pStartCrsr
->GetPoint();
80 if( !bCheckEmpty
|| ( pStt
!= pEnd
&& *pStt
!= *pEnd
))
84 SwRubyListEntry
* pNew
= new SwRubyListEntry
;
88 *aPam
.GetMark() = *pEnd
;
90 if( _SelectNextRubyChars( aPam
, *pNew
, nMode
))
92 rList
.Insert( pNew
, rList
.Count() );
98 if( *aPam
.GetPoint() < *pEnd
)
100 // goto next paragraph
102 aPam
.Move( fnMoveForward
, fnGoNode
);
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
,
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
;
128 const SwPosition
* pStt
= _pStartCrsr
->Start(),
129 * pEnd
= pStt
== _pStartCrsr
->GetPoint()
130 ? _pStartCrsr
->GetMark()
131 : _pStartCrsr
->GetPoint();
132 if( !bCheckEmpty
|| ( pStt
!= pEnd
&& *pStt
!= *pEnd
))
137 SwRubyListEntry aCheckEntry
;
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 );
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
);
165 if( *aPam
.GetPoint() < *pEnd
)
167 // goto next paragraph
169 aPam
.Move( fnMoveForward
, fnGoNode
);
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 );
181 aPam
.GetMark()->nContent
-= pEntry
->GetText().Len();
182 Insert( aPam
, pEntry
->GetRubyAttr(), nsSetAttrMode::SETATTR_DONTEXPAND
);
189 } while( nListEntry
< rList
.Count() && *aPam
.GetPoint() < *pEnd
);
191 } while( 30 > rList
.Count() &&
192 (_pStartCrsr
=(SwPaM
*)_pStartCrsr
->GetNext()) != __pStartCrsr
);
194 EndUndo( UNDO_SETRUBYATTR
, NULL
);
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();
211 if( rPam
.GetMark()->nNode
== pPos
->nNode
)
214 xub_StrLen nTEnd
= rPam
.GetMark()->nContent
.GetIndex();
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;
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
)
236 if( !bHasMark
&& nStart
> *pAttr
->GetStart() )
238 nStart
= *pAttr
->GetStart();
239 pPos
->nContent
= nStart
;
246 if( !bHasMark
&& nStart
&& ( !pAttr
|| nStart
!= *pAttr
->GetStart()) )
248 // skip to the word begin!
249 long nWordStt
= pBreakIt
->GetBreakIter()->getWordBoundary(
251 pBreakIt
->GetLocale( pTNd
->GetLang( nStart
)),
252 WordType::ANYWORD_IGNOREWHITESPACES
,
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() )
272 pPos
->nContent
= *pAttr
->GetAnyEnd();
273 if( pPos
->nContent
.GetIndex() > nEnd
)
274 pPos
->nContent
= nEnd
;
275 rEntry
.SetRubyAttr( pAttr
->GetRuby() );
280 sal_Int32 nChType
= rCC
.getType( *pTxt
, nStart
);
281 BOOL bIgnoreChar
= FALSE
, bIsAlphaNum
= FALSE
, bChkNxtWrd
= FALSE
;
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
;
291 case UnicodeType::SPACE_SEPARATOR
:
292 case UnicodeType::CONTROL
:
293 /*??*/ case UnicodeType::PRIVATE_USE
:
294 case UnicodeType::START_PUNCTUATION
:
295 case UnicodeType::END_PUNCTUATION
:
300 case UnicodeType::OTHER_LETTER
:
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:
331 if( bIgnoreChar
|| bIsAlphaNum
!= bAlphaNum
|| nStart
>= nWordEnd
)
334 else if( !bIgnoreChar
)
337 bAlphaNum
= bIsAlphaNum
;
338 if( bChkNxtWrd
&& pBreakIt
->GetBreakIter().is() )
340 // search the end of this word
341 nWordEnd
= pBreakIt
->GetBreakIter()->getWordBoundary(
343 pBreakIt
->GetLocale( pTNd
->GetLang( nStart
)),
344 WordType::ANYWORD_IGNOREWHITESPACES
,
346 if( 0 > nWordEnd
|| nWordEnd
> nEnd
|| nWordEnd
== nStart
)
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()