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 #ifdef DBG_UTIL 32 33 /* -----------------08.01.99 14:55------------------- 34 * Und hier die Beschreibung: 35 * 36 * Durch die PROTOCOL-Makros wird es ermoeglicht, Ereignisse im Frame-Methoden zu protokollieren. 37 * In protokollwuerdigen Stellen in Frame-Methoden muss entweder ein PROTOCOL(...) oder bei Methoden, 38 * bei denen auch das Verlassen der Methode mitprotokolliert werden soll, ein PROTOCOL_ENTER(...)-Makro 39 * stehen. 40 * Die Parameter der PROTOCOL-Makros sind 41 * 1. Ein Pointer auf einen SwFrm, also meist "this" oder "rThis" 42 * 2. Die Funktionsgruppe z.B. PROT_MAKEALL, hierueber wird (inline) entschieden, ob dies 43 * zur Zeit protokolliert werden soll oder nicht. 44 * 3. Die Aktion, im Normalfall 0, aber z.B. ein ACT_START bewirkt eine Einrueckung in der 45 * Ausgabedatei, ein ACT_END nimmt dies wieder zurueck. Auf diese Art wird z.B. durch 46 * PROTOCOL_ENTER am Anfang einer Methode eingerueckt und beim Verlassen wieder zurueck. 47 * 4. Der vierte Parameter ist ein void-Pointer, damit man irgendetwas uebergeben kann, 48 * was in das Protokoll einfliessen kann, typesches Beispiel bei PROT_GROW muss man 49 * einen Pointer auf den Wert, um den gegrowt werden soll, uebergeben. 50 * 51 * 52 * Das Protokoll ist die Datei "dbg_lay.out" im aktuellen (BIN-)Verzeichnis. 53 * Es enthaelt Zeilen mit FrmId, Funktionsgruppe sowie weiteren Infos. 54 * 55 * Was genau protokolliert wird, kann auf folgende Arten eingestellt werden: 56 * 1. Die statische Variable SwProtokoll::nRecord enthaelt die Funktionsgruppen, 57 * die aufgezeichnet werden sollen. 58 * Ein Wert von z.B. PROT_GROW bewirkt, das Aufrufe von SwFrm::Grow dokumentiert werden, 59 * PROT_MAKEALL protokolliert Aufrufe von xxx::MakeAll. 60 * Die PROT_XY-Werte koennen oderiert werden. 61 * Default ist Null, es wird keine Methode aufgezeichnet. 62 * 2. In der SwImplProtocol-Klasse gibt es einen Filter fuer Frame-Typen, 63 * nur die Methodenaufrufe von Frame-Typen, die dort gesetzt sind, werden protokolliert. 64 * Der Member nTypes kann auf Werte wie FRM_PAGE, FRM_SECTION gesetzt und oderiert werden. 65 * Default ist 0xFFFF, d.h. alle Frame-Typen. 66 * 3. In der SwImplProtocol-Klasse gibt es einen ArrayPointer auf FrmIds, die zu ueberwachen sind. 67 * Ist der Pointer Null, so werden alle Frames protokolliert, ansonsten nur Frames, 68 * die in dem Array vermerkt sind. 69 * 70 * Eine Aufzeichnung in Gang zu setzen, erfordert entweder Codemanipulation, z.B. in 71 * SwProtocol::Init() einen anderen Default fuer nRecord setzen oder Debuggermanipulation. 72 * Im Debugger gibt verschiedene, sich anbietende Stellen: 73 * 1. In SwProtocol::Init() einen Breakpoint setzen und dort nRecord manipulieren, ggf. 74 * FrmIds eintragen, dann beginnt die Aufzeichnung bereits beim Programmstart. 75 * 2. Waehrend des Programmlaufs einen Breakpoint vor irgendein PROTOCOL oder PROTOCOL_ENTER- 76 * Makro setzen, dann am SwProtocol::nRecord das unterste Bit setzen (PROT_INIT). Dies 77 * bewirkt, dass die Funktionsgruppe des folgenden Makros aktiviert und in Zukunft 78 * protokolliert wird. 79 * 3. Spezialfall von 2.: Wenn man 2. in der Methode SwRootFrm::Paint(..) anwendet, werden 80 * die Aufzeichnungseinstellung aus der Datei "dbg_lay.ini" ausgelesen! 81 * In dieser INI-Datei kann es Kommentarzeilen geben, diese beginnen mit '#', dann 82 * sind die Sektionen "[frmid]", "[frmtype]" und "[record]" relevant. 83 * Nach [frmid] koennen die FrameIds der zu protokollierenden Frames folgen. Gibt es 84 * dort keine Eintraege, werden alle Frames aufgezeichnet. 85 * Nach [frmtype] koennen FrameTypen folgen, die aufgezeichnet werden sollen, da der 86 * Default hier allerdings USHRT_MAX ist, werden sowieso alle aufgezeichnet. Man kann 87 * allerdings auch Typen entfernen, in dem man ein '!' vor den Wert setzt, z.B. 88 * !0xC000 nimmt die SwCntntFrms aus der Aufzeichnung heraus. 89 * Nach [record] folgen die Funktionsgruppen, die aufgezeichnet werden sollen, Default 90 * ist hier 0, also keine. Auch hier kann man mit einem vorgestellten '!' Funktionen 91 * wieder entfernen. 92 * Hier mal ein Beispiel fuer eine INI-Datei: 93 * ------------------------------------------ 94 * #Funktionen: Alle, ausser PRTAREA 95 * [record] 0xFFFFFFE !0x200 96 * [frmid] 97 * #folgende FrmIds: 98 * 1 2 12 13 14 15 99 * #keine Layoutframes ausser ColumnFrms 100 * [frmtype] !0x3FFF 0x4 101 * ------------------------------------------ 102 * 103 * Wenn die Aufzeichnung erstmal laeuft, kann man in SwImplProtocol::_Record(...) mittels 104 * Debugger vielfaeltige Manipulationen vornehmen, z.B. bezueglich FrameTypen oder FrmIds. 105 * 106 * --------------------------------------------------*/ 107 108 #ifndef DBG_UTIL 109 #error Wer fummelt denn an den makefiles rum? 110 #endif 111 112 113 114 #include "dbg_lay.hxx" 115 #include <tools/stream.hxx> 116 117 #ifndef _SVSTDARR_HXX 118 #define _SVSTDARR_USHORTS 119 #define _SVSTDARR_USHORTSSORT 120 #define _SVSTDARR_LONGS 121 #include <svl/svstdarr.hxx> 122 #endif 123 124 #include <stdio.h> 125 126 #include "frame.hxx" 127 #include "layfrm.hxx" 128 #include "flyfrm.hxx" 129 #include "txtfrm.hxx" 130 #include "ndtxt.hxx" 131 #include "dflyobj.hxx" 132 #include <fntcache.hxx> 133 // OD 2004-05-24 #i28701# 134 #include <sortedobjs.hxx> 135 136 sal_uLong SwProtocol::nRecord = 0; 137 SwImplProtocol* SwProtocol::pImpl = NULL; 138 139 sal_uLong lcl_GetFrameId( const SwFrm* pFrm ) 140 { 141 #ifdef DBG_UTIL 142 static sal_Bool bFrameId = sal_False; 143 if( bFrameId ) 144 return pFrm->GetFrmId(); 145 #endif 146 if( pFrm && pFrm->IsTxtFrm() ) 147 return ((SwTxtFrm*)pFrm)->GetTxtNode()->GetIndex(); 148 return 0; 149 } 150 151 class SwImplProtocol 152 { 153 SvFileStream *pStream; // Ausgabestream 154 SvUShortsSort *pFrmIds; // welche FrmIds sollen aufgezeichnet werden ( NULL == alle ) 155 SvLongs *pVar; // Variables 156 ByteString aLayer; // Einrueckung der Ausgabe (" " pro Start/End) 157 sal_uInt16 nTypes; // welche Typen sollen aufgezeichnet werden 158 sal_uInt16 nLineCount; // Ausgegebene Zeilen 159 sal_uInt16 nMaxLines; // Maximal auszugebende Zeilen 160 sal_uInt8 nInitFile; // Bereich (FrmId,FrmType,Record) beim Einlesen der INI-Datei 161 sal_uInt8 nTestMode; // Special fuer Testformatierung, es wird ggf. nur 162 // innerhalb einer Testformatierung aufgezeichnet. 163 void _Record( const SwFrm* pFrm, sal_uLong nFunction, sal_uLong nAct, void* pParam ); 164 sal_Bool NewStream(); 165 void CheckLine( ByteString& rLine ); 166 void SectFunc( ByteString &rOut, const SwFrm* pFrm, sal_uLong nAct, void* pParam ); 167 public: 168 SwImplProtocol(); 169 ~SwImplProtocol(); 170 // Aufzeichnen 171 void Record( const SwFrm* pFrm, sal_uLong nFunction, sal_uLong nAct, void* pParam ) 172 { if( pStream ) _Record( pFrm, nFunction, nAct, pParam ); } 173 sal_Bool InsertFrm( sal_uInt16 nFrmId ); // FrmId aufnehmen zum Aufzeichnen 174 sal_Bool DeleteFrm( sal_uInt16 nFrmId ); // FrmId entfernen, diesen nicht mehr Aufzeichnen 175 void FileInit(); // Auslesen der INI-Datei 176 void ChkStream() { if( !pStream ) NewStream(); } 177 void SnapShot( const SwFrm* pFrm, sal_uLong nFlags ); 178 void GetVar( const sal_uInt16 nNo, long& rVar ) 179 { if( pVar && nNo < pVar->Count() ) rVar = (*pVar)[ nNo ]; } 180 }; 181 182 /* -----------------11.01.99 10:43------------------- 183 * Durch das PROTOCOL_ENTER-Makro wird ein SwEnterLeave-Objekt erzeugt, 184 * wenn die aktuelle Funktion aufgezeichnet werden soll, wird ein 185 * SwImplEnterLeave-Objekt angelegt. Der Witz dabei ist, das der Ctor 186 * des Impl-Objekt am Anfang der Funktion und automatisch der Dtor beim 187 * Verlassen der Funktion gerufen wird. In der Basis-Implementierung ruft 188 * der Ctor lediglich ein PROTOCOL(..) mit ACT_START und im Dtor ein 189 * PROTOCOL(..) mit ACT_END. 190 * Es lassen sich Ableitungen der Klasse bilden, um z.B. beim Verlassen 191 * einer Funktion Groessenaenderungen des Frames zu dokumentieren u.v.a.m. 192 * Dazu braucht dann nur noch in SwEnterLeave::Ctor(...) die gewuenschte 193 * SwImplEnterLeave-Klasse angelegt zu werden. 194 * 195 * --------------------------------------------------*/ 196 197 class SwImplEnterLeave 198 { 199 protected: 200 const SwFrm* pFrm; // Der Frame, 201 sal_uLong nFunction, nAction; // die Funktion, ggf. die Aktion 202 void* pParam; // und weitere Parameter 203 public: 204 SwImplEnterLeave( const SwFrm* pF, sal_uLong nFunct, sal_uLong nAct, void* pPar ) 205 : pFrm( pF ), nFunction( nFunct ), nAction( nAct ), pParam( pPar ) {} 206 virtual void Enter(); // Ausgabe beim Eintritt 207 virtual void Leave(); // Ausgabe beim Verlassen 208 }; 209 210 class SwSizeEnterLeave : public SwImplEnterLeave 211 { 212 long nFrmHeight; 213 public: 214 SwSizeEnterLeave( const SwFrm* pF, sal_uLong nFunct, sal_uLong nAct, void* pPar ) 215 : SwImplEnterLeave( pF, nFunct, nAct, pPar ), nFrmHeight( pF->Frm().Height() ) {} 216 virtual void Leave(); // Ausgabe der Groessenaenderung 217 }; 218 219 class SwUpperEnterLeave : public SwImplEnterLeave 220 { 221 sal_uInt16 nFrmId; 222 public: 223 SwUpperEnterLeave( const SwFrm* pF, sal_uLong nFunct, sal_uLong nAct, void* pPar ) 224 : SwImplEnterLeave( pF, nFunct, nAct, pPar ), nFrmId( 0 ) {} 225 virtual void Enter(); // Ausgabe 226 virtual void Leave(); // Ausgabe der FrmId des Uppers 227 }; 228 229 class SwFrmChangesLeave : public SwImplEnterLeave 230 { 231 SwRect aFrm; 232 public: 233 SwFrmChangesLeave( const SwFrm* pF, sal_uLong nFunct, sal_uLong nAct, void* pPar ) 234 : SwImplEnterLeave( pF, nFunct, nAct, pPar ), aFrm( pF->Frm() ) {} 235 virtual void Enter(); // keine Ausgabe 236 virtual void Leave(); // Ausgabe bei Aenderung der Frm-Area 237 }; 238 239 void SwProtocol::Record( const SwFrm* pFrm, sal_uLong nFunction, sal_uLong nAct, void* pParam ) 240 { 241 if( Start() ) 242 { // Hier landen wir, wenn im Debugger SwProtocol::nRecord mit PROT_INIT(0x1) oderiert wurde 243 sal_Bool bFinit = sal_False; // Dies bietet im Debugger die Moeglichkeit, 244 if( bFinit ) // die Aufzeichnung dieser Action zu beenden 245 { 246 nRecord &= ~nFunction; // Diese Funktion nicht mehr aufzeichnen 247 nRecord &= ~PROT_INIT; // PROT_INIT stets zuruecksetzen 248 return; 249 } 250 nRecord |= nFunction; // Aufzeichnung dieser Funktion freischalten 251 nRecord &= ~PROT_INIT; // PROT_INIT stets zuruecksetzen 252 if( pImpl ) 253 pImpl->ChkStream(); 254 } 255 if( !pImpl ) // Impl-Object anlegen, wenn noetig 256 pImpl = new SwImplProtocol(); 257 pImpl->Record( pFrm, nFunction, nAct, pParam ); // ...und Aufzeichnen 258 } 259 260 // Die folgende Funktion wird beim Anziehen der Writer-DLL durch TxtInit(..) aufgerufen 261 // und ermoeglicht dem Debuggenden Funktionen und/oder FrmIds freizuschalten 262 263 void SwProtocol::Init() 264 { 265 nRecord = 0; 266 XubString aName( "dbg_lay.go", RTL_TEXTENCODING_MS_1252 ); 267 SvFileStream aStream( aName, STREAM_READ ); 268 if( aStream.IsOpen() ) 269 { 270 pImpl = new SwImplProtocol(); 271 pImpl->FileInit(); 272 } 273 aStream.Close(); 274 } 275 276 // Ende der Aufzeichnung 277 278 void SwProtocol::Stop() 279 { 280 if( pImpl ) 281 { 282 delete pImpl; 283 pImpl = NULL; 284 if( pFntCache ) 285 pFntCache->Flush(); 286 } 287 nRecord = 0; 288 } 289 290 // Creates a more or less detailed snapshot of the layout structur 291 292 void SwProtocol::SnapShot( const SwFrm* pFrm, sal_uLong nFlags ) 293 { 294 if( pImpl ) 295 pImpl->SnapShot( pFrm, nFlags ); 296 } 297 298 void SwProtocol::GetVar( const sal_uInt16 nNo, long& rVar ) 299 { 300 if( pImpl ) 301 pImpl->GetVar( nNo, rVar ); 302 } 303 304 SwImplProtocol::SwImplProtocol() 305 : pStream( NULL ), pFrmIds( NULL ), pVar( NULL ), nTypes( 0xffff ), 306 nLineCount( 0 ), nMaxLines( USHRT_MAX ), nTestMode( 0 ) 307 { 308 NewStream(); 309 } 310 311 sal_Bool SwImplProtocol::NewStream() 312 { 313 XubString aName( "dbg_lay.out", RTL_TEXTENCODING_MS_1252 ); 314 nLineCount = 0; 315 pStream = new SvFileStream( aName, STREAM_WRITE | STREAM_TRUNC ); 316 if( pStream->GetError() ) 317 { 318 delete pStream; 319 pStream = NULL; 320 } 321 return 0 != pStream; 322 } 323 324 SwImplProtocol::~SwImplProtocol() 325 { 326 if( pStream ) 327 { 328 pStream->Close(); 329 delete pStream; 330 } 331 delete pFrmIds; 332 delete pVar; 333 } 334 335 /* -----------------11.01.99 11:03------------------- 336 * SwImplProtocol::CheckLine analysiert eine Zeile der INI-Datei 337 * --------------------------------------------------*/ 338 339 void SwImplProtocol::CheckLine( ByteString& rLine ) 340 { 341 rLine = rLine.ToLowerAscii(); // Gross/Kleinschreibung ist einerlei 342 while( STRING_LEN > rLine.SearchAndReplace( '\t', ' ' ) ) 343 ; //nothing // Tabs werden durch Blanks ersetzt 344 if( '#' == rLine.GetChar(0) ) // Kommentarzeilen beginnen mit '#' 345 return; 346 if( '[' == rLine.GetChar(0) ) // Bereiche: FrmIds, Typen oder Funktionen 347 { 348 ByteString aTmp = rLine.GetToken( 0, ']' ); 349 if( "[frmid" == aTmp ) // Bereich FrmIds 350 { 351 nInitFile = 1; 352 delete pFrmIds; 353 pFrmIds = NULL; // Default: Alle Frames aufzeichnen 354 } 355 else if( "[frmtype" == aTmp )// Bereich Typen 356 { 357 nInitFile = 2; 358 nTypes = USHRT_MAX; // Default: Alle FrmaeTypen aufzeichnen 359 } 360 else if( "[record" == aTmp )// Bereich Funktionen 361 { 362 nInitFile = 3; 363 SwProtocol::SetRecord( 0 );// Default: Keine Funktion wird aufgezeichnet 364 } 365 else if( "[test" == aTmp )// Bereich Funktionen 366 { 367 nInitFile = 4; // Default: 368 nTestMode = 0; // Ausserhalb der Testformatierung wird aufgezeichnet 369 } 370 else if( "[max" == aTmp )// maximale Zeilenzahl 371 { 372 nInitFile = 5; // Default: 373 nMaxLines = USHRT_MAX; 374 } 375 else if( "[var" == aTmp )// variables 376 { 377 nInitFile = 6; 378 if( !pVar ) 379 pVar = new SvLongs( 5, 5 ); 380 } 381 else 382 nInitFile = 0; // Nanu: Unbekannter Bereich? 383 rLine.Erase( 0, aTmp.Len() + 1 ); 384 } 385 sal_uInt16 nToks = rLine.GetTokenCount( ' ' ); // Blanks (oder Tabs) sind die Trenner 386 for( sal_uInt16 i=0; i < nToks; ++i ) 387 { 388 ByteString aTok = rLine.GetToken( i, ' ' ); 389 sal_Bool bNo = sal_False; 390 if( '!' == aTok.GetChar(0) ) 391 { 392 bNo = sal_True; // Diese(n) Funktion/Typ entfernen 393 aTok.Erase( 0, 1 ); 394 } 395 if( aTok.Len() ) 396 { 397 sal_uLong nVal; 398 sscanf( aTok.GetBuffer(), "%li", &nVal ); 399 switch ( nInitFile ) 400 { 401 case 1: InsertFrm( sal_uInt16( nVal ) ); // FrmId aufnehmen 402 break; 403 case 2: { 404 sal_uInt16 nNew = (sal_uInt16)nVal; 405 if( bNo ) 406 nTypes &= ~nNew; // Typ entfernen 407 else 408 nTypes |= nNew; // Typ aufnehmen 409 } 410 break; 411 case 3: { 412 sal_uLong nOld = SwProtocol::Record(); 413 if( bNo ) 414 nOld &= ~nVal; // Funktion entfernen 415 else 416 nOld |= nVal; // Funktion aufnehmen 417 SwProtocol::SetRecord( nOld ); 418 } 419 break; 420 case 4: { 421 sal_uInt8 nNew = (sal_uInt8)nVal; 422 if( bNo ) 423 nTestMode &= ~nNew; // TestMode zuruecksetzen 424 else 425 nTestMode |= nNew; // TestMode setzen 426 } 427 break; 428 case 5: nMaxLines = (sal_uInt16)nVal; 429 break; 430 case 6: pVar->Insert( (long)nVal, pVar->Count() ); 431 break; 432 } 433 } 434 } 435 } 436 437 /* -----------------11.01.99 11:17------------------- 438 * SwImplProtocol::FileInit() liest die Datei "dbg_lay.ini" 439 * im aktuellen Verzeichnis und wertet sie aus. 440 * --------------------------------------------------*/ 441 void SwImplProtocol::FileInit() 442 { 443 XubString aName( "dbg_lay.ini", RTL_TEXTENCODING_MS_1252 ); 444 SvFileStream aStream( aName, STREAM_READ ); 445 if( aStream.IsOpen() ) 446 { 447 ByteString aLine; 448 nInitFile = 0; 449 while( !aStream.IsEof() ) 450 { 451 sal_Char c; 452 aStream >> c; 453 if( '\n' == c || '\r' == c ) // Zeilenende 454 { 455 aLine.EraseLeadingChars(); 456 aLine.EraseTrailingChars(); 457 if( aLine.Len() ) 458 CheckLine( aLine ); // Zeile auswerten 459 aLine.Erase(); 460 } 461 else 462 aLine += c; 463 } 464 if( aLine.Len() ) 465 CheckLine( aLine ); // letzte Zeile auswerten 466 } 467 aStream.Close(); 468 } 469 470 /* -----------------11.01.99 11:20------------------- 471 * lcl_Start sorgt fuer Einrueckung um zwei Blanks bei ACT_START 472 * und nimmt diese bei ACT_END wieder zurueck. 473 * --------------------------------------------------*/ 474 void lcl_Start( ByteString& rOut, ByteString& rLay, sal_uLong nAction ) 475 { 476 if( nAction == ACT_START ) 477 { 478 rLay += " "; 479 rOut += " On"; 480 } 481 else if( nAction == ACT_END ) 482 { 483 if( rLay.Len() > 1 ) 484 { 485 rLay.Erase( rLay.Len() - 2 ); 486 rOut.Erase( 0, 2 ); 487 } 488 rOut += " Off"; 489 } 490 } 491 492 /* -----------------11.01.99 11:21------------------- 493 * lcl_Flags gibt das ValidSize-, ValidPos- und ValidPrtArea-Flag ("Sz","Ps","PA") 494 * des Frames aus, "+" fuer valid, "-" fuer invalid. 495 * --------------------------------------------------*/ 496 497 void lcl_Flags( ByteString& rOut, const SwFrm* pFrm ) 498 { 499 rOut += " Sz"; 500 rOut += pFrm->GetValidSizeFlag() ? '+' : '-'; 501 rOut += " Ps"; 502 rOut += pFrm->GetValidPosFlag() ? '+' : '-'; 503 rOut += " PA"; 504 rOut += pFrm->GetValidPrtAreaFlag() ? '+' : '-'; 505 } 506 507 /* -----------------11.01.99 11:23------------------- 508 * lcl_FrameType gibt den Typ des Frames in Klartext aus. 509 * --------------------------------------------------*/ 510 511 void lcl_FrameType( ByteString& rOut, const SwFrm* pFrm ) 512 { 513 if( pFrm->IsTxtFrm() ) 514 rOut += "Txt "; 515 else if( pFrm->IsLayoutFrm() ) 516 { 517 if( pFrm->IsPageFrm() ) 518 rOut += "Page "; 519 else if( pFrm->IsColumnFrm() ) 520 rOut += "Col "; 521 else if( pFrm->IsBodyFrm() ) 522 { 523 if( pFrm->GetUpper() && pFrm->IsColBodyFrm() ) 524 rOut += "(Col)"; 525 rOut += "Body "; 526 } 527 else if( pFrm->IsRootFrm() ) 528 rOut += "Root "; 529 else if( pFrm->IsCellFrm() ) 530 rOut += "Cell "; 531 else if( pFrm->IsTabFrm() ) 532 rOut += "Tab "; 533 else if( pFrm->IsRowFrm() ) 534 rOut += "Row "; 535 else if( pFrm->IsSctFrm() ) 536 rOut += "Sect "; 537 else if( pFrm->IsHeaderFrm() ) 538 rOut += "Header "; 539 else if( pFrm->IsFooterFrm() ) 540 rOut += "Footer "; 541 else if( pFrm->IsFtnFrm() ) 542 rOut += "Ftn "; 543 else if( pFrm->IsFtnContFrm() ) 544 rOut += "FtnCont "; 545 else if( pFrm->IsFlyFrm() ) 546 rOut += "Fly "; 547 else 548 rOut += "Layout "; 549 } 550 else if( pFrm->IsNoTxtFrm() ) 551 rOut += "NoTxt "; 552 else 553 rOut += "Not impl. "; 554 } 555 556 /* -----------------11.01.99 11:25------------------- 557 * SwImplProtocol::Record(..) wird nur gerufen, wenn das PROTOCOL-Makro 558 * feststellt, dass die Funktion aufgezeichnet werden soll ( SwProtocol::nRecord ). 559 * In dieser Methode werden noch die beiden weiteren Einschraenkungen ueberprueft, 560 * ob die FrmId und der FrameType zu den aufzuzeichnenden gehoeren. 561 * --------------------------------------------------*/ 562 563 void SwImplProtocol::_Record( const SwFrm* pFrm, sal_uLong nFunction, sal_uLong nAct, void* pParam ) 564 { 565 sal_uInt16 nSpecial = 0; 566 if( nSpecial ) // Debugger-Manipulationsmoeglichkeit 567 { 568 sal_uInt16 nId = sal_uInt16(lcl_GetFrameId( pFrm )); 569 switch ( nSpecial ) 570 { 571 case 1: InsertFrm( nId ); break; 572 case 2: DeleteFrm( nId ); break; 573 case 3: delete pFrmIds; pFrmIds = NULL; break; 574 case 4: delete pStream; pStream = NULL; break; 575 } 576 return; 577 } 578 if( !pStream && !NewStream() ) 579 return; // Immer noch kein Stream 580 581 if( pFrmIds && !pFrmIds->Seek_Entry( sal_uInt16(lcl_GetFrameId( pFrm )) ) ) 582 return; // gehoert nicht zu den gewuenschten FrmIds 583 584 if( !(pFrm->GetType() & nTypes) ) 585 return; // Der Typ ist unerwuenscht 586 587 if( 1 == nTestMode && nFunction != PROT_TESTFORMAT ) 588 return; // Wir sollen nur innerhalb einer Testformatierung aufzeichnen 589 sal_Bool bTmp = sal_False; 590 ByteString aOut = aLayer; 591 aOut += ByteString::CreateFromInt64( lcl_GetFrameId( pFrm ) ); 592 aOut += ' '; 593 lcl_FrameType( aOut, pFrm ); // dann den FrameType 594 switch ( nFunction ) // und die Funktion 595 { 596 case PROT_SNAPSHOT: lcl_Flags( aOut, pFrm ); 597 break; 598 case PROT_MAKEALL: aOut += "MakeAll"; 599 lcl_Start( aOut, aLayer, nAct ); 600 if( nAct == ACT_START ) 601 lcl_Flags( aOut, pFrm ); 602 break; 603 case PROT_MOVE_FWD: bTmp = sal_True; // NoBreak 604 case PROT_MOVE_BWD: aOut += ( nFunction == bTmp ) ? "Fwd" : "Bwd"; 605 lcl_Start( aOut, aLayer, nAct ); 606 if( pParam ) 607 { 608 aOut += ' '; 609 aOut += ByteString::CreateFromInt32( *((sal_uInt16*)pParam) ); 610 } 611 break; 612 case PROT_GROW_TST: if( ACT_START != nAct ) 613 return; 614 aOut += "TestGrow"; 615 break; 616 case PROT_SHRINK_TST: if( ACT_START != nAct ) 617 return; 618 aOut += "TestShrink"; 619 break; 620 case PROT_ADJUSTN : 621 case PROT_SHRINK: bTmp = sal_True; // NoBreak 622 case PROT_GROW: aOut += !bTmp ? "Grow" : 623 ( nFunction == PROT_SHRINK ? "Shrink" : "AdjustNgbhd" ); 624 lcl_Start( aOut, aLayer, nAct ); 625 if( pParam ) 626 { 627 aOut += ' '; 628 aOut += ByteString::CreateFromInt64( *((long*)pParam) ); 629 } 630 break; 631 case PROT_POS: break; 632 case PROT_PRTAREA: aOut += "PrtArea"; 633 lcl_Start( aOut, aLayer, nAct ); 634 break; 635 case PROT_SIZE: aOut += "Size"; 636 lcl_Start( aOut, aLayer, nAct ); 637 aOut += ' '; 638 aOut += ByteString::CreateFromInt64( pFrm->Frm().Height() ); 639 break; 640 case PROT_LEAF: aOut += "Prev/NextLeaf"; 641 lcl_Start( aOut, aLayer, nAct ); 642 aOut += ' '; 643 if( pParam ) 644 { 645 aOut += ' '; 646 aOut += ByteString::CreateFromInt64( lcl_GetFrameId( (SwFrm*)pParam ) ); 647 } 648 break; 649 case PROT_FILE_INIT: FileInit(); 650 aOut = "Initialize"; 651 break; 652 case PROT_SECTION: SectFunc( aOut, pFrm, nAct, pParam ); 653 break; 654 case PROT_CUT: bTmp = sal_True; // NoBreak 655 case PROT_PASTE: aOut += bTmp ? "Cut from " : "Paste to "; 656 aOut += ByteString::CreateFromInt64( lcl_GetFrameId( (SwFrm*)pParam ) ); 657 break; 658 case PROT_TESTFORMAT: aOut += "Test"; 659 lcl_Start( aOut, aLayer, nAct ); 660 if( ACT_START == nAct ) 661 nTestMode |= 2; 662 else 663 nTestMode &= ~2; 664 break; 665 case PROT_FRMCHANGES: 666 { 667 SwRect& rFrm = *((SwRect*)pParam); 668 if( pFrm->Frm().Pos() != rFrm.Pos() ) 669 { 670 aOut += "PosChg: ("; 671 aOut += ByteString::CreateFromInt64(rFrm.Left()); 672 aOut += ", "; 673 aOut += ByteString::CreateFromInt64(rFrm.Top()); 674 aOut += ") ("; 675 aOut += ByteString::CreateFromInt64(pFrm->Frm().Left()); 676 aOut += ", "; 677 aOut += ByteString::CreateFromInt64(pFrm->Frm().Top()); 678 aOut += ") "; 679 } 680 if( pFrm->Frm().Height() != rFrm.Height() ) 681 { 682 aOut += "Height: "; 683 aOut += ByteString::CreateFromInt64(rFrm.Height()); 684 aOut += " -> "; 685 aOut += ByteString::CreateFromInt64(pFrm->Frm().Height()); 686 aOut += " "; 687 } 688 if( pFrm->Frm().Width() != rFrm.Width() ) 689 { 690 aOut += "Width: "; 691 aOut += ByteString::CreateFromInt64(rFrm.Width()); 692 aOut += " -> "; 693 aOut += ByteString::CreateFromInt64(pFrm->Frm().Width()); 694 aOut += " "; 695 } 696 break; 697 } 698 } 699 *pStream << aOut.GetBuffer() << endl; // Ausgabe 700 pStream->Flush(); // Gleich auf die Platte, damit man mitlesen kann 701 if( ++nLineCount >= nMaxLines ) // Maximale Ausgabe erreicht? 702 SwProtocol::SetRecord( 0 ); // => Ende der Aufzeichnung 703 } 704 705 /* -----------------13.01.99 11:39------------------- 706 * SwImplProtocol::SectFunc(...) wird von SwImplProtocol::_Record(..) gerufen, 707 * hier werden die Ausgaben rund um SectionFrms abgehandelt. 708 * --------------------------------------------------*/ 709 710 void SwImplProtocol::SectFunc( ByteString &rOut, const SwFrm* , sal_uLong nAct, void* pParam ) 711 { 712 sal_Bool bTmp = sal_False; 713 switch( nAct ) 714 { 715 case ACT_MERGE: rOut += "Merge Section "; 716 rOut += ByteString::CreateFromInt64( lcl_GetFrameId( (SwFrm*)pParam ) ); 717 break; 718 case ACT_CREATE_MASTER: bTmp = sal_True; // NoBreak 719 case ACT_CREATE_FOLLOW: rOut += "Create Section "; 720 rOut += bTmp ? "Master to " : "Follow from "; 721 rOut += ByteString::CreateFromInt64( lcl_GetFrameId( (SwFrm*)pParam ) ); 722 break; 723 case ACT_DEL_MASTER: bTmp = sal_True; // NoBreak 724 case ACT_DEL_FOLLOW: rOut += "Delete Section "; 725 rOut += bTmp ? "Master to " : "Follow from "; 726 rOut += ByteString::CreateFromInt64( lcl_GetFrameId( (SwFrm*)pParam ) ); 727 break; 728 } 729 } 730 731 /* -----------------11.01.99 11:31------------------- 732 * SwImplProtocol::InsertFrm(..) nimmt eine neue FrmId zum Aufzeichnen auf, 733 * wenn pFrmIds==NULL, werden alle aufgezeichnet, sobald durch InsertFrm(..) 734 * pFrmIds angelegt wird, werden nur noch die enthaltenen FrmIds aufgezeichnet. 735 * --------------------------------------------------*/ 736 737 sal_Bool SwImplProtocol::InsertFrm( sal_uInt16 nId ) 738 { 739 if( !pFrmIds ) 740 pFrmIds = new SvUShortsSort(5,5); 741 if( pFrmIds->Seek_Entry( nId ) ) 742 return sal_False; 743 pFrmIds->Insert( nId ); 744 return sal_True; 745 } 746 747 /* -----------------11.01.99 11:52------------------- 748 * SwImplProtocol::DeleteFrm(..) entfernt eine FrmId aus dem pFrmIds-Array, 749 * so dass diese Frame nicht mehr aufgezeichnet wird. 750 * --------------------------------------------------*/ 751 sal_Bool SwImplProtocol::DeleteFrm( sal_uInt16 nId ) 752 { 753 sal_uInt16 nPos; 754 if( !pFrmIds || !pFrmIds->Seek_Entry( nId, &nPos ) ) 755 return sal_False; 756 pFrmIds->Remove( nPos ); 757 return sal_True; 758 } 759 760 /*-----------------20.9.2001 10:29------------------ 761 * SwProtocol::SnapShot(..) 762 * creates a snapshot of the given frame and its content. 763 * --------------------------------------------------*/ 764 void SwImplProtocol::SnapShot( const SwFrm* pFrm, sal_uLong nFlags ) 765 { 766 while( pFrm ) 767 { 768 _Record( pFrm, PROT_SNAPSHOT, 0, 0); 769 if( pFrm->GetDrawObjs() && nFlags & SNAP_FLYFRAMES ) 770 { 771 aLayer += "[ "; 772 const SwSortedObjs &rObjs = *pFrm->GetDrawObjs(); 773 for ( sal_uInt16 i = 0; i < rObjs.Count(); ++i ) 774 { 775 SwAnchoredObject* pObj = rObjs[i]; 776 if ( pObj->ISA(SwFlyFrm) ) 777 SnapShot( static_cast<SwFlyFrm*>(pObj), nFlags ); 778 } 779 if( aLayer.Len() > 1 ) 780 aLayer.Erase( aLayer.Len() - 2 ); 781 } 782 if( pFrm->IsLayoutFrm() && nFlags & SNAP_LOWER && 783 ( !pFrm->IsTabFrm() || nFlags & SNAP_TABLECONT ) ) 784 { 785 aLayer += " "; 786 SnapShot( ((SwLayoutFrm*)pFrm)->Lower(), nFlags ); 787 if( aLayer.Len() > 1 ) 788 aLayer.Erase( aLayer.Len() - 2 ); 789 } 790 pFrm = pFrm->GetNext(); 791 } 792 } 793 794 /* -----------------11.01.99 11:53------------------- 795 * SwEnterLeave::Ctor(..) wird vom eigentlichen (inline-)Kontruktor gerufen, 796 * wenn die Funktion aufgezeichnet werden soll. 797 * Die Aufgabe ist es abhaengig von der Funktion das richtige SwImplEnterLeave-Objekt 798 * zu erzeugen, alles weitere geschieht dann in dessen Ctor/Dtor. 799 * --------------------------------------------------*/ 800 void SwEnterLeave::Ctor( const SwFrm* pFrm, sal_uLong nFunc, sal_uLong nAct, void* pPar ) 801 { 802 switch( nFunc ) 803 { 804 case PROT_ADJUSTN : 805 case PROT_GROW: 806 case PROT_SHRINK : pImpl = new SwSizeEnterLeave( pFrm, nFunc, nAct, pPar ); break; 807 case PROT_MOVE_FWD: 808 case PROT_MOVE_BWD : pImpl = new SwUpperEnterLeave( pFrm, nFunc, nAct, pPar ); break; 809 case PROT_FRMCHANGES : pImpl = new SwFrmChangesLeave( pFrm, nFunc, nAct, pPar ); break; 810 default: pImpl = new SwImplEnterLeave( pFrm, nFunc, nAct, pPar ); break; 811 } 812 pImpl->Enter(); 813 } 814 815 /* -----------------11.01.99 11:56------------------- 816 * SwEnterLeave::Dtor() ruft lediglich den Destruktor des SwImplEnterLeave-Objekts, 817 * ist nur deshalb nicht inline, damit die SwImplEnterLeave-Definition nicht 818 * im dbg_lay.hxx zu stehen braucht. 819 * --------------------------------------------------*/ 820 821 void SwEnterLeave::Dtor() 822 { 823 if( pImpl ) 824 { 825 pImpl->Leave(); 826 delete pImpl; 827 } 828 } 829 830 void SwImplEnterLeave::Enter() 831 { 832 SwProtocol::Record( pFrm, nFunction, ACT_START, pParam ); 833 } 834 835 void SwImplEnterLeave::Leave() 836 { 837 SwProtocol::Record( pFrm, nFunction, ACT_END, pParam ); 838 } 839 840 void SwSizeEnterLeave::Leave() 841 { 842 nFrmHeight = pFrm->Frm().Height() - nFrmHeight; 843 SwProtocol::Record( pFrm, nFunction, ACT_END, &nFrmHeight ); 844 } 845 846 void SwUpperEnterLeave::Enter() 847 { 848 nFrmId = pFrm->GetUpper() ? sal_uInt16(lcl_GetFrameId( pFrm->GetUpper() )) : 0; 849 SwProtocol::Record( pFrm, nFunction, ACT_START, &nFrmId ); 850 } 851 852 void SwUpperEnterLeave::Leave() 853 { 854 nFrmId = pFrm->GetUpper() ? sal_uInt16(lcl_GetFrameId( pFrm->GetUpper() )) : 0; 855 SwProtocol::Record( pFrm, nFunction, ACT_END, &nFrmId ); 856 } 857 858 void SwFrmChangesLeave::Enter() 859 { 860 } 861 862 void SwFrmChangesLeave::Leave() 863 { 864 if( pFrm->Frm() != aFrm ) 865 SwProtocol::Record( pFrm, PROT_FRMCHANGES, 0, &aFrm ); 866 } 867 868 #endif // DBG_UTIL 869 870