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() )
151 InsertPoolItem( aPam
, pEntry
->GetRubyAttr(), 0 );
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 );
169 if( *aPam
.GetPoint() < *pEnd
)
171 // goto next paragraph
173 aPam
.Move( fnMoveForward
, fnGoNode
);
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() );
185 aPam
.GetMark()->nContent
-= pEntry
->GetText().Len();
186 InsertPoolItem( aPam
, pEntry
->GetRubyAttr(),
187 nsSetAttrMode::SETATTR_DONTEXPAND
);
194 } while( nListEntry
< rList
.Count() && *aPam
.GetPoint() < *pEnd
);
196 } while( 30 > rList
.Count() &&
197 (_pStartCrsr
=(SwPaM
*)_pStartCrsr
->GetNext()) != __pStartCrsr
);
199 EndUndo( UNDO_SETRUBYATTR
, NULL
);
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();
216 if( rPam
.GetMark()->nNode
== pPos
->nNode
)
219 xub_StrLen nTEnd
= rPam
.GetMark()->nContent
.GetIndex();
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;
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
)
241 if( !bHasMark
&& nStart
> *pAttr
->GetStart() )
243 nStart
= *pAttr
->GetStart();
244 pPos
->nContent
= nStart
;
251 if( !bHasMark
&& nStart
&& ( !pAttr
|| nStart
!= *pAttr
->GetStart()) )
253 // skip to the word begin!
254 long nWordStt
= pBreakIt
->GetBreakIter()->getWordBoundary(
256 pBreakIt
->GetLocale( pTNd
->GetLang( nStart
)),
257 WordType::ANYWORD_IGNOREWHITESPACES
,
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() )
277 pPos
->nContent
= *pAttr
->GetAnyEnd();
278 if( pPos
->nContent
.GetIndex() > nEnd
)
279 pPos
->nContent
= nEnd
;
280 rEntry
.SetRubyAttr( pAttr
->GetRuby() );
285 sal_Int32 nChType
= rCC
.getType( *pTxt
, nStart
);
286 BOOL bIgnoreChar
= FALSE
, bIsAlphaNum
= FALSE
, bChkNxtWrd
= FALSE
;
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
;
296 case UnicodeType::SPACE_SEPARATOR
:
297 case UnicodeType::CONTROL
:
298 /*??*/ case UnicodeType::PRIVATE_USE
:
299 case UnicodeType::START_PUNCTUATION
:
300 case UnicodeType::END_PUNCTUATION
:
305 case UnicodeType::OTHER_LETTER
:
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:
336 if( bIgnoreChar
|| bIsAlphaNum
!= bAlphaNum
|| nStart
>= nWordEnd
)
339 else if( !bIgnoreChar
)
342 bAlphaNum
= bIsAlphaNum
;
343 if( bChkNxtWrd
&& pBreakIt
->GetBreakIter().is() )
345 // search the end of this word
346 nWordEnd
= pBreakIt
->GetBreakIter()->getWordBoundary(
348 pBreakIt
->GetLocale( pTNd
->GetLang( nStart
)),
349 WordType::ANYWORD_IGNOREWHITESPACES
,
351 if( 0 > nWordEnd
|| nWordEnd
> nEnd
|| nWordEnd
== nStart
)
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()