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