1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_svtools.hxx" 26 27 #include <svtools/textdata.hxx> 28 #include <textdat2.hxx> 29 30 #include <tools/debug.hxx> 31 32 SV_IMPL_PTRARR( TextLines, TextLinePtr ); 33 SV_IMPL_VARARR( TEWritingDirectionInfos, TEWritingDirectionInfo ); 34 35 36 // ------------------------------------------------------------------------- 37 // (+) class TextSelection 38 // ------------------------------------------------------------------------- 39 40 TextSelection::TextSelection() 41 { 42 } 43 44 TextSelection::TextSelection( const TextPaM& rPaM ) : 45 maStartPaM( rPaM ), maEndPaM( rPaM ) 46 { 47 } 48 49 TextSelection::TextSelection( const TextPaM& rStart, const TextPaM& rEnd ) : 50 maStartPaM( rStart ), maEndPaM( rEnd ) 51 { 52 } 53 54 void TextSelection::Justify() 55 { 56 if ( maEndPaM < maStartPaM ) 57 { 58 TextPaM aTemp( maStartPaM ); 59 maStartPaM = maEndPaM; 60 maEndPaM = aTemp; 61 } 62 } 63 64 65 // ------------------------------------------------------------------------- 66 // (+) class TETextPortionList 67 // ------------------------------------------------------------------------- 68 TETextPortionList::TETextPortionList() 69 { 70 } 71 72 TETextPortionList::~TETextPortionList() 73 { 74 Reset(); 75 } 76 77 void TETextPortionList::Reset() 78 { 79 for ( sal_uInt16 nPortion = 0; nPortion < Count(); nPortion++ ) 80 delete GetObject( nPortion ); 81 Remove( 0, Count() ); 82 } 83 84 void TETextPortionList::DeleteFromPortion( sal_uInt16 nDelFrom ) 85 { 86 DBG_ASSERT( ( nDelFrom < Count() ) || ( (nDelFrom == 0) && (Count() == 0) ), "DeleteFromPortion: Out of range" ); 87 for ( sal_uInt16 nP = nDelFrom; nP < Count(); nP++ ) 88 delete GetObject( nP ); 89 Remove( nDelFrom, Count()-nDelFrom ); 90 } 91 92 sal_uInt16 TETextPortionList::FindPortion( sal_uInt16 nCharPos, sal_uInt16& nPortionStart, sal_Bool bPreferStartingPortion ) 93 { 94 // Bei nCharPos an Portion-Grenze wird die linke Portion gefunden 95 sal_uInt16 nTmpPos = 0; 96 for ( sal_uInt16 nPortion = 0; nPortion < Count(); nPortion++ ) 97 { 98 TETextPortion* pPortion = GetObject( nPortion ); 99 nTmpPos = nTmpPos + pPortion->GetLen(); 100 if ( nTmpPos >= nCharPos ) 101 { 102 // take this one if we don't prefer the starting portion, or if it's the last one 103 if ( ( nTmpPos != nCharPos ) || !bPreferStartingPortion || ( nPortion == Count() - 1 ) ) 104 { 105 nPortionStart = nTmpPos - pPortion->GetLen(); 106 return nPortion; 107 } 108 } 109 } 110 DBG_ERROR( "FindPortion: Nicht gefunden!" ); 111 return ( Count() - 1 ); 112 } 113 114 /* 115 sal_uInt16 TETextPortionList::GetPortionStartIndex( sal_uInt16 nPortion ) 116 { 117 sal_uInt16 nPos = 0; 118 for ( sal_uInt16 nP = 0; nP < nPortion; nP++ ) 119 { 120 TETextPortion* pPortion = GetObject( nP ); 121 nPos += pPortion->GetLen(); 122 } 123 return nPos; 124 } 125 */ 126 127 128 // ------------------------------------------------------------------------- 129 // (+) class TEParaPortion 130 // ------------------------------------------------------------------------- 131 TEParaPortion::TEParaPortion( TextNode* pN ) 132 { 133 mpNode = pN; 134 mnInvalidPosStart = mnInvalidDiff = 0; 135 mbInvalid = sal_True; 136 mbSimple = sal_False; 137 } 138 139 TEParaPortion::~TEParaPortion() 140 { 141 } 142 143 void TEParaPortion::MarkInvalid( sal_uInt16 nStart, short nDiff ) 144 { 145 if ( mbInvalid == sal_False ) 146 { 147 mnInvalidPosStart = ( nDiff >= 0 ) ? nStart : ( nStart + nDiff ); 148 mnInvalidDiff = nDiff; 149 } 150 else 151 { 152 // Einfaches hintereinander tippen 153 if ( ( nDiff > 0 ) && ( mnInvalidDiff > 0 ) && 154 ( ( mnInvalidPosStart+mnInvalidDiff ) == nStart ) ) 155 { 156 mnInvalidDiff = mnInvalidDiff + nDiff; 157 } 158 // Einfaches hintereinander loeschen 159 else if ( ( nDiff < 0 ) && ( mnInvalidDiff < 0 ) && ( mnInvalidPosStart == nStart ) ) 160 { 161 mnInvalidPosStart = mnInvalidPosStart + nDiff; 162 mnInvalidDiff = mnInvalidDiff + nDiff; 163 } 164 else 165 { 166 DBG_ASSERT( ( nDiff >= 0 ) || ( (nStart+nDiff) >= 0 ), "MarkInvalid: Diff out of Range" ); 167 mnInvalidPosStart = Min( mnInvalidPosStart, (sal_uInt16) ( (nDiff < 0) ? nStart+nDiff : nDiff ) ); 168 mnInvalidDiff = 0; 169 mbSimple = sal_False; 170 } 171 } 172 173 maWritingDirectionInfos.Remove( 0, maWritingDirectionInfos.Count() ); 174 175 mbInvalid = sal_True; 176 } 177 178 void TEParaPortion::MarkSelectionInvalid( sal_uInt16 nStart, sal_uInt16 /*nEnd*/ ) 179 { 180 if ( mbInvalid == sal_False ) 181 { 182 mnInvalidPosStart = nStart; 183 // nInvalidPosEnd = nEnd; 184 } 185 else 186 { 187 mnInvalidPosStart = Min( mnInvalidPosStart, nStart ); 188 // nInvalidPosEnd = pNode->Len(); 189 } 190 191 maWritingDirectionInfos.Remove( 0, maWritingDirectionInfos.Count() ); 192 193 mnInvalidDiff = 0; 194 mbInvalid = sal_True; 195 mbSimple = sal_False; 196 } 197 198 sal_uInt16 TEParaPortion::GetLineNumber( sal_uInt16 nChar, sal_Bool bInclEnd ) 199 { 200 for ( sal_uInt16 nLine = 0; nLine < maLines.Count(); nLine++ ) 201 { 202 TextLine* pLine = maLines.GetObject( nLine ); 203 if ( ( bInclEnd && ( pLine->GetEnd() >= nChar ) ) || 204 ( pLine->GetEnd() > nChar ) ) 205 { 206 return nLine; 207 } 208 } 209 210 // Dann sollte es am Ende der letzten Zeile sein! 211 DBG_ASSERT( nChar == maLines[ maLines.Count() - 1 ]->GetEnd(), "Index voll daneben!" ); 212 DBG_ASSERT( !bInclEnd, "Zeile nicht gefunden: FindLine" ); 213 return ( maLines.Count() - 1 ); 214 } 215 216 217 void TEParaPortion::CorrectValuesBehindLastFormattedLine( sal_uInt16 nLastFormattedLine ) 218 { 219 sal_uInt16 nLines = maLines.Count(); 220 DBG_ASSERT( nLines, "CorrectPortionNumbersFromLine: Leere Portion?" ); 221 if ( nLastFormattedLine < ( nLines - 1 ) ) 222 { 223 const TextLine* pLastFormatted = maLines[ nLastFormattedLine ]; 224 const TextLine* pUnformatted = maLines[ nLastFormattedLine+1 ]; 225 short nPortionDiff = pUnformatted->GetStartPortion() - pLastFormatted->GetEndPortion(); 226 short nTextDiff = pUnformatted->GetStart() - pLastFormatted->GetEnd(); 227 nTextDiff++; // LastFormatted->GetEnd() war incl. => 1 zuviel abgezogen! 228 229 // Die erste unformatierte muss genau eine Portion hinter der letzten der 230 // formatierten beginnen: 231 // Wenn in der geaenderten Zeile eine Portion gesplittet wurde, 232 // kann nLastEnd > nNextStart sein! 233 short nPDiff = sal::static_int_cast< short >(-( nPortionDiff-1 )); 234 short nTDiff = sal::static_int_cast< short >(-( nTextDiff-1 )); 235 if ( nPDiff || nTDiff ) 236 { 237 for ( sal_uInt16 nL = nLastFormattedLine+1; nL < nLines; nL++ ) 238 { 239 TextLine* pLine = maLines[ nL ]; 240 241 pLine->GetStartPortion() = pLine->GetStartPortion() + nPDiff; 242 pLine->GetEndPortion() = pLine->GetEndPortion() + nPDiff; 243 244 pLine->GetStart() = pLine->GetStart() + nTDiff; 245 pLine->GetEnd() = pLine->GetEnd() + nTDiff; 246 247 pLine->SetValid(); 248 } 249 } 250 } 251 } 252 253 // ------------------------------------------------------------------------- 254 // (+) class TEParaPortions 255 // ------------------------------------------------------------------------- 256 TEParaPortions::TEParaPortions() 257 { 258 } 259 260 TEParaPortions::~TEParaPortions() 261 { 262 Reset(); 263 } 264 265 void TEParaPortions::Reset() 266 { 267 TEParaPortions::iterator aIter( begin() ); 268 while ( aIter != end() ) 269 delete *aIter++; 270 clear(); 271 } 272 273 // ------------------------------------------------------------------------- 274 // (+) class IdleFormatter 275 // ------------------------------------------------------------------------- 276 IdleFormatter::IdleFormatter() 277 { 278 mpView = 0; 279 mnRestarts = 0; 280 } 281 282 IdleFormatter::~IdleFormatter() 283 { 284 mpView = 0; 285 } 286 287 void IdleFormatter::DoIdleFormat( TextView* pV, sal_uInt16 nMaxRestarts ) 288 { 289 mpView = pV; 290 291 if ( IsActive() ) 292 mnRestarts++; 293 294 if ( mnRestarts > nMaxRestarts ) 295 { 296 mnRestarts = 0; 297 ((Link&)GetTimeoutHdl()).Call( this ); 298 } 299 else 300 { 301 Start(); 302 } 303 } 304 305 void IdleFormatter::ForceTimeout() 306 { 307 if ( IsActive() ) 308 { 309 Stop(); 310 mnRestarts = 0; 311 ((Link&)GetTimeoutHdl()).Call( this ); 312 } 313 } 314 315 TYPEINIT1( TextHint, SfxSimpleHint ); 316 317 TextHint::TextHint( sal_uLong Id ) : SfxSimpleHint( Id ) 318 { 319 mnValue = 0; 320 } 321 322 TextHint::TextHint( sal_uLong Id, sal_uLong nValue ) : SfxSimpleHint( Id ) 323 { 324 mnValue = nValue; 325 } 326 327 TEIMEInfos::TEIMEInfos( const TextPaM& rPos, const String& rOldTextAfterStartPos ) 328 : aOldTextAfterStartPos( rOldTextAfterStartPos ) 329 { 330 aPos = rPos; 331 nLen = 0; 332 bCursor = sal_True; 333 pAttribs = NULL; 334 bWasCursorOverwrite = sal_False; 335 } 336 337 TEIMEInfos::~TEIMEInfos() 338 { 339 delete[] pAttribs; 340 } 341 342 void TEIMEInfos::CopyAttribs( const sal_uInt16* pA, sal_uInt16 nL ) 343 { 344 nLen = nL; 345 delete pAttribs; 346 pAttribs = new sal_uInt16[ nL ]; 347 memcpy( pAttribs, pA, nL*sizeof(sal_uInt16) ); 348 } 349 350 void TEIMEInfos::DestroyAttribs() 351 { 352 delete pAttribs; 353 pAttribs = NULL; 354 nLen = 0; 355 } 356 357 358