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