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